Skip to content

Commit 7584ac2

Browse files
fix: 🐛 修复Notice在Tabbar页面时跳转至其他页面导致播放异常的问题并提供reset方法 (#680)
Closes: #358,Closes: #650
1 parent dae135d commit 7584ac2

5 files changed

Lines changed: 164 additions & 68 deletions

File tree

docs/component/notice-bar.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,40 @@ const onNext = (index: number) => {
115115
<wd-notice-bar prefix="warn-bold" direction="vertical" text="只有一条消息不会滚动" :speed="0.5" :delay="3" custom-class="space" />
116116
```
117117

118+
## 重置播放动画 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.3.13</el-tag>
119+
通过`ref`获取组件实例,调用`reset`方法即可重置播放动画。当你遇到`NoticeBar`的播放动画异常的情况时,可以调用`reset`方法重置动画。
120+
121+
例如:在`APP-VUE`端,`Tabbar`页面使用`NoticeBar`时,从其它界面返回到`NoticeBar`页面,会偶发`NoticeBar`动画异常,此时可以调用`reset`方法重置动画。
122+
123+
参考issues:[#358](https://github.com/Moonofweisheng/wot-design-uni/issues/358)[#650](https://github.com/Moonofweisheng/wot-design-uni/issues/650)
124+
125+
```html
126+
<wd-notice-bar ref="notice" prefix="warn-bold" direction="vertical" :text="textArray" :delay="3" />
127+
<wd-button @click="handleReset">重置播放动画</wd-button>
128+
```
129+
130+
```ts
131+
// uni_modules
132+
import { type NoticeBarInstance } from '@/uni_modules/wot-design-uni/components/wd-notice-bar/types'
133+
// npm
134+
// import { type NoticeBarInstance } from 'wot-design-uni/components/wd-notice-bar/types'
135+
136+
const notice = ref<NoticeBarInstance>()
137+
138+
const textArray = ref([
139+
'欢迎使用wot design uni',
140+
'该组件库基于uniapp ->Vue3, ts构建',
141+
'项目地址:https://github.com/Moonofweisheng/wot-design-uni',
142+
'我们的目标是打造最强uniapp组件库',
143+
'诚挚邀请大家共同建设',
144+
'这是一条消息提示信息,这是一条消息提示信息,这是一条消息提示信息,这是一条消息提示信息,这是一条消息提示信息'
145+
])
146+
147+
function handleReset() {
148+
notice.value?.reset()
149+
}
150+
```
151+
118152
## Attributes
119153

120154
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
@@ -139,6 +173,12 @@ const onNext = (index: number) => {
139173
| next | 下一次滚动前触发 | index: `number` | - |
140174
| click | 点击时触发 | `{ text: string, index: number }`,其中`text`为当前文本,`index`为当前文本索引 | 1.2.16 |
141175

176+
## Methods
177+
178+
| 方法名称 | 说明 | 参数 | 最低版本 |
179+
|---------|-----|-----|---------|
180+
| reset | 用于重置播放动画| - | $LOWEST_VERSION$ |
181+
142182
## Slot
143183

144184
| name | 说明 | 类型 | 最低版本 |

src/pages/noticeBar/Index.vue

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
<!--
2-
* @Author: weisheng
3-
* @Date: 2023-06-13 11:47:12
4-
* @LastEditTime: 2024-04-16 13:13:31
5-
* @LastEditors: weisheng
6-
* @Description:
7-
* @FilePath: \wot-design-uni\src\pages\noticeBar\Index.vue
8-
* 记得注释
9-
-->
101
<template>
112
<page-wraper>
123
<view>
@@ -73,12 +64,25 @@
7364
<wd-notice-bar @click="handleClick" prefix="warn-bold" direction="vertical" :text="textArray" :delay="3" custom-class="space" />
7465
<wd-notice-bar @click="handleClick" prefix="warn-bold" direction="vertical" text="只有一条消息不会滚动" :delay="3" custom-class="space" />
7566
</demo-block>
67+
68+
<demo-block title="重置播放动画">
69+
<wd-notice-bar ref="notice" prefix="warn-bold" direction="vertical" :text="textArray" :delay="3" custom-class="space" />
70+
71+
<wd-button @click="handleReset">重置播放动画</wd-button>
72+
</demo-block>
7673
</view>
7774
</page-wraper>
7875
</template>
7976
<script lang="ts" setup>
77+
import { type NoticeBarInstance } from '@/uni_modules/wot-design-uni/components/wd-notice-bar/types'
8078
import { ref } from 'vue'
8179
80+
const notice = ref<NoticeBarInstance>()
81+
82+
function handleReset() {
83+
notice.value?.reset()
84+
}
85+
8286
const textArray = ref([
8387
'欢迎使用wot design uni',
8488
'该组件库基于uniapp ->Vue3, ts构建',

src/uni_modules/wot-design-uni/components/wd-notice-bar/index.scss

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@
4848
@include e(content) {
4949
position: absolute;
5050
white-space: nowrap;
51-
52-
@include m(play) {
53-
animation: notice-bar-play linear both;
54-
}
55-
@include m(play-infinite) {
56-
animation: notice-bar-play-infinite linear infinite both;
57-
}
5851
}
5952
@include m(ellipse) {
6053
.wd-notice-bar__content {
@@ -72,16 +65,4 @@
7265
white-space: normal;
7366
}
7467
}
75-
}
76-
77-
@keyframes notice-bar-play {
78-
100% {
79-
transform: translate3d(-100%, 0, 0);
80-
}
81-
}
82-
83-
@keyframes notice-bar-play-infinite {
84-
100% {
85-
transform: translate3d(-100%, 0, 0);
86-
}
87-
}
68+
}

src/uni_modules/wot-design-uni/components/wd-notice-bar/types.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { PropType } from 'vue'
1+
import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
22
import { baseProps, makeBooleanProp, makeNumberProp, makeStringProp } from '../common/props'
33

44
export type NoticeBarType = 'warning' | 'info' | 'danger' | ''
@@ -54,3 +54,14 @@ export const noticeBarProps = {
5454
*/
5555
direction: makeStringProp<NoticeBarScrollDirection>('horizontal')
5656
}
57+
58+
export type NoticeBarProps = ExtractPropTypes<typeof noticeBarProps>
59+
60+
export type NoticeBarExpose = {
61+
/**
62+
* 重置NoticeBar动画
63+
*/
64+
reset: () => void
65+
}
66+
67+
export type NoticeBarInstance = ComponentPublicInstance<NoticeBarProps, NoticeBarExpose>

src/uni_modules/wot-design-uni/components/wd-notice-bar/wd-notice-bar.vue

Lines changed: 98 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,9 @@ export default {
2828

2929
<script lang="ts" setup>
3030
import wdIcon from '../wd-icon/wd-icon.vue'
31-
import { ref, watch, nextTick, computed, getCurrentInstance, type CSSProperties } from 'vue'
31+
import { ref, watch, nextTick, computed, getCurrentInstance, type CSSProperties, onMounted, onActivated, onDeactivated, reactive } from 'vue'
3232
import { getRect, isArray, isDef, objToStyle } from '../common/util'
33-
import { noticeBarProps } from './types'
34-
33+
import { type NoticeBarExpose, noticeBarProps } from './types'
3534
const $wrap = '.wd-notice-bar__wrap'
3635
const $content = '.wd-notice-bar__content'
3736
@@ -40,14 +39,27 @@ const emit = defineEmits(['close', 'next', 'click'])
4039
4140
const wrapWidth = ref<number>(0)
4241
const show = ref<boolean>(true)
43-
const animation = ref<string>('')
44-
const currentIndex = ref(0)
42+
const currentIndex = ref<number>(0)
4543
const textArray = computed(() => (Array.isArray(props.text) ? props.text : [props.text]))
4644
const currentText = computed(() => textArray.value[currentIndex.value])
47-
const verticalIndex = ref(0)
45+
const verticalIndex = ref<number>(0)
46+
const wrapRect = ref<UniApp.NodeInfo | null>(null) // 外层容器节点信息
47+
const contentRect = ref<UniApp.NodeInfo | null>(null) // 内容节点信息
4848
const isHorizontal = computed(() => props.direction === 'horizontal')
4949
const isVertical = computed(() => props.direction === 'vertical')
5050
51+
const transitionState = reactive<CSSProperties>({
52+
transitionProperty: 'unset',
53+
transitionDelay: 'unset',
54+
transitionDuration: 'unset',
55+
transform: 'none',
56+
transitionTimingFunction: 'linear'
57+
})
58+
59+
const animation = computed(() => {
60+
return objToStyle(transitionState)
61+
})
62+
5163
const rootStyle = computed(() => {
5264
const style: CSSProperties = {}
5365
if (isDef(props.color)) {
@@ -79,28 +91,66 @@ const noticeBarClass = computed(() => {
7991
const { proxy } = getCurrentInstance() as any
8092
8193
watch(
82-
[() => props.text],
94+
() => props.text,
8395
() => {
84-
nextTick(() => scroll())
96+
reset()
8597
},
86-
{ deep: true, immediate: true }
98+
{ deep: true }
8799
)
88100
101+
onMounted(() => {
102+
startTransition()
103+
// #ifdef APP-PLUS
104+
const pages = getCurrentPages()
105+
const currentPage = pages[pages.length - 1]
106+
const currentWebview = currentPage.$getAppWebview!()
107+
currentWebview.addEventListener('hide', () => {
108+
stopTransition()
109+
})
110+
currentWebview.addEventListener('show', () => {
111+
startTransition()
112+
})
113+
// #endif
114+
})
115+
116+
onActivated(() => {
117+
startTransition()
118+
})
119+
120+
onDeactivated(() => {
121+
stopTransition()
122+
})
123+
124+
function reset() {
125+
stopTransition()
126+
startTransition()
127+
}
128+
129+
function startTransition() {
130+
nextTick(() => scroll())
131+
}
132+
133+
function stopTransition() {
134+
transitionState.transitionProperty = 'unset'
135+
transitionState.transitionDelay = 'unset'
136+
transitionState.transitionDuration = 'unset'
137+
transitionState.transform = 'none'
138+
transitionState.transitionTimingFunction = 'linear'
139+
currentIndex.value = 0
140+
verticalIndex.value = 0
141+
}
142+
89143
function handleClose() {
90144
show.value = false
91145
emit('close')
92146
}
93147
94-
function initAnimation({ duration, delay, translate }: { duration: number; delay: number; translate: number }) {
95-
const style: CSSProperties = {
96-
transitionProperty: 'all',
97-
transitionDelay: `${delay}s`,
98-
transitionDuration: `${duration}s`,
99-
transform: `${props.direction === 'vertical' ? 'translateY' : 'translateX'}(${translate}px)`,
100-
transitionTimingFunction: 'linear'
101-
}
102-
103-
return objToStyle(style)
148+
function setTransition({ duration, delay, translate }: { duration: number; delay: number; translate: number }) {
149+
transitionState.transitionProperty = 'all'
150+
transitionState.transitionDelay = `${delay}s`
151+
transitionState.transitionDuration = `${duration}s`
152+
transitionState.transform = `${props.direction === 'vertical' ? 'translateY' : 'translateX'}(${translate}px)`
153+
transitionState.transitionTimingFunction = 'linear'
104154
}
105155
106156
function queryRect() {
@@ -109,30 +159,31 @@ function queryRect() {
109159
110160
async function verticalAnimate(height: number) {
111161
const translate = -(height / (textArray.value.length + 1)) * (currentIndex.value + 1)
112-
animation.value = initAnimation({
162+
setTransition({
113163
duration: height / (textArray.value.length + 1) / props.speed,
114164
delay: props.delay,
115165
translate
116166
})
117167
}
118168
119169
async function scroll() {
120-
const [wrapRect, contentRect] = await queryRect()
121-
if (!wrapRect.width || !contentRect.width || !contentRect.height) return
122-
123-
wrapWidth.value = wrapRect.width
170+
const [wRect, cRect] = await queryRect()
171+
if (!wRect.width || !cRect.width || !cRect.height) return
172+
wrapRect.value = wRect
173+
contentRect.value = cRect
174+
wrapWidth.value = wRect.width
124175
125176
if (isHorizontal.value) {
126177
if (props.scrollable) {
127-
animation.value = initAnimation({
128-
duration: contentRect.width / props.speed,
178+
setTransition({
179+
duration: cRect.width / props.speed,
129180
delay: props.delay,
130-
translate: -contentRect.width
181+
translate: -cRect.width
131182
})
132183
}
133184
} else {
134185
if (textArray.value.length > 1) {
135-
verticalAnimate(contentRect.height)
186+
verticalAnimate(cRect.height)
136187
}
137188
}
138189
}
@@ -148,15 +199,15 @@ function next() {
148199
149200
function animationEnd() {
150201
if (isHorizontal.value) {
151-
animation.value = initAnimation({
202+
setTransition({
152203
duration: 0,
153204
delay: 0,
154-
translate: wrapWidth.value + 1 // +1容错空间,防止露出来一丢丢
205+
translate: wrapWidth.value + 1
155206
})
156207
} else {
157208
if (++verticalIndex.value >= textArray.value.length) {
158209
verticalIndex.value = 0
159-
animation.value = initAnimation({
210+
setTransition({
160211
duration: 0,
161212
delay: 0,
162213
translate: 0
@@ -168,18 +219,25 @@ function animationEnd() {
168219
next() // 更换下一条文本
169220
170221
nextTick(async () => {
171-
// 因为文本会发生变化,所以每一次都需要查询
172-
const [_, contentRect] = await queryRect()
173-
if (!contentRect.width || !contentRect.height) return
222+
try {
223+
const [wRect, cRect] = await queryRect()
224+
wrapRect.value = wRect
225+
contentRect.value = cRect
226+
wrapWidth.value = wRect.width || 0
227+
} catch (error) {
228+
// console.error(error)
229+
}
230+
231+
if (!contentRect.value || !contentRect.value.width || !contentRect.value.height) return
174232
175233
if (isHorizontal.value) {
176-
animation.value = initAnimation({
177-
duration: (wrapWidth.value + contentRect.width) / props.speed,
234+
setTransition({
235+
duration: (wrapWidth.value + contentRect.value.width) / props.speed,
178236
delay: props.delay,
179-
translate: -contentRect.width
237+
translate: -contentRect.value.width
180238
})
181239
} else {
182-
verticalAnimate(contentRect.height)
240+
verticalAnimate(contentRect.value.height)
183241
}
184242
})
185243
@@ -199,6 +257,8 @@ function handleClick() {
199257
}
200258
emit('click', result)
201259
}
260+
261+
defineExpose<NoticeBarExpose>({ reset })
202262
</script>
203263

204264
<style lang="scss" scoped>

0 commit comments

Comments
 (0)