Skip to content

Commit

Permalink
fix: 🐛 修复Notice在Tabbar页面时跳转至其他页面导致播放异常的问题并提供reset方法 (#680)
Browse files Browse the repository at this point in the history
Closes: #358,Closes: #650
  • Loading branch information
Moonofweisheng authored Oct 24, 2024
1 parent dae135d commit 7584ac2
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 68 deletions.
40 changes: 40 additions & 0 deletions docs/component/notice-bar.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,40 @@ const onNext = (index: number) => {
<wd-notice-bar prefix="warn-bold" direction="vertical" text="只有一条消息不会滚动" :speed="0.5" :delay="3" custom-class="space" />
```

## 重置播放动画 <el-tag text style="vertical-align: middle;margin-left:8px;" effect="plain">1.3.13</el-tag>
通过`ref`获取组件实例,调用`reset`方法即可重置播放动画。当你遇到`NoticeBar`的播放动画异常的情况时,可以调用`reset`方法重置动画。

例如:在`APP-VUE`端,`Tabbar`页面使用`NoticeBar`时,从其它界面返回到`NoticeBar`页面,会偶发`NoticeBar`动画异常,此时可以调用`reset`方法重置动画。

参考issues:[#358](https://github.com/Moonofweisheng/wot-design-uni/issues/358)[#650](https://github.com/Moonofweisheng/wot-design-uni/issues/650)

```html
<wd-notice-bar ref="notice" prefix="warn-bold" direction="vertical" :text="textArray" :delay="3" />
<wd-button @click="handleReset">重置播放动画</wd-button>
```

```ts
// uni_modules
import { type NoticeBarInstance } from '@/uni_modules/wot-design-uni/components/wd-notice-bar/types'
// npm
// import { type NoticeBarInstance } from 'wot-design-uni/components/wd-notice-bar/types'

const notice = ref<NoticeBarInstance>()

const textArray = ref([
'欢迎使用wot design uni',
'该组件库基于uniapp ->Vue3, ts构建',
'项目地址:https://github.com/Moonofweisheng/wot-design-uni',
'我们的目标是打造最强uniapp组件库',
'诚挚邀请大家共同建设',
'这是一条消息提示信息,这是一条消息提示信息,这是一条消息提示信息,这是一条消息提示信息,这是一条消息提示信息'
])

function handleReset() {
notice.value?.reset()
}
```

## Attributes

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

## Methods

| 方法名称 | 说明 | 参数 | 最低版本 |
|---------|-----|-----|---------|
| reset | 用于重置播放动画| - | $LOWEST_VERSION$ |

## Slot

| name | 说明 | 类型 | 最低版本 |
Expand Down
22 changes: 13 additions & 9 deletions src/pages/noticeBar/Index.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
<!--
* @Author: weisheng
* @Date: 2023-06-13 11:47:12
* @LastEditTime: 2024-04-16 13:13:31
* @LastEditors: weisheng
* @Description:
* @FilePath: \wot-design-uni\src\pages\noticeBar\Index.vue
* 记得注释
-->
<template>
<page-wraper>
<view>
Expand Down Expand Up @@ -73,12 +64,25 @@
<wd-notice-bar @click="handleClick" prefix="warn-bold" direction="vertical" :text="textArray" :delay="3" custom-class="space" />
<wd-notice-bar @click="handleClick" prefix="warn-bold" direction="vertical" text="只有一条消息不会滚动" :delay="3" custom-class="space" />
</demo-block>

<demo-block title="重置播放动画">
<wd-notice-bar ref="notice" prefix="warn-bold" direction="vertical" :text="textArray" :delay="3" custom-class="space" />

<wd-button @click="handleReset">重置播放动画</wd-button>
</demo-block>
</view>
</page-wraper>
</template>
<script lang="ts" setup>
import { type NoticeBarInstance } from '@/uni_modules/wot-design-uni/components/wd-notice-bar/types'
import { ref } from 'vue'
const notice = ref<NoticeBarInstance>()
function handleReset() {
notice.value?.reset()
}
const textArray = ref([
'欢迎使用wot design uni',
'该组件库基于uniapp ->Vue3, ts构建',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,6 @@
@include e(content) {
position: absolute;
white-space: nowrap;

@include m(play) {
animation: notice-bar-play linear both;
}
@include m(play-infinite) {
animation: notice-bar-play-infinite linear infinite both;
}
}
@include m(ellipse) {
.wd-notice-bar__content {
Expand All @@ -72,16 +65,4 @@
white-space: normal;
}
}
}

@keyframes notice-bar-play {
100% {
transform: translate3d(-100%, 0, 0);
}
}

@keyframes notice-bar-play-infinite {
100% {
transform: translate3d(-100%, 0, 0);
}
}
}
13 changes: 12 additions & 1 deletion src/uni_modules/wot-design-uni/components/wd-notice-bar/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { PropType } from 'vue'
import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
import { baseProps, makeBooleanProp, makeNumberProp, makeStringProp } from '../common/props'

export type NoticeBarType = 'warning' | 'info' | 'danger' | ''
Expand Down Expand Up @@ -54,3 +54,14 @@ export const noticeBarProps = {
*/
direction: makeStringProp<NoticeBarScrollDirection>('horizontal')
}

export type NoticeBarProps = ExtractPropTypes<typeof noticeBarProps>

export type NoticeBarExpose = {
/**
* 重置NoticeBar动画
*/
reset: () => void
}

export type NoticeBarInstance = ComponentPublicInstance<NoticeBarProps, NoticeBarExpose>
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@ export default {

<script lang="ts" setup>
import wdIcon from '../wd-icon/wd-icon.vue'
import { ref, watch, nextTick, computed, getCurrentInstance, type CSSProperties } from 'vue'
import { ref, watch, nextTick, computed, getCurrentInstance, type CSSProperties, onMounted, onActivated, onDeactivated, reactive } from 'vue'
import { getRect, isArray, isDef, objToStyle } from '../common/util'
import { noticeBarProps } from './types'
import { type NoticeBarExpose, noticeBarProps } from './types'
const $wrap = '.wd-notice-bar__wrap'
const $content = '.wd-notice-bar__content'
Expand All @@ -40,14 +39,27 @@ const emit = defineEmits(['close', 'next', 'click'])
const wrapWidth = ref<number>(0)
const show = ref<boolean>(true)
const animation = ref<string>('')
const currentIndex = ref(0)
const currentIndex = ref<number>(0)
const textArray = computed(() => (Array.isArray(props.text) ? props.text : [props.text]))
const currentText = computed(() => textArray.value[currentIndex.value])
const verticalIndex = ref(0)
const verticalIndex = ref<number>(0)
const wrapRect = ref<UniApp.NodeInfo | null>(null) // 外层容器节点信息
const contentRect = ref<UniApp.NodeInfo | null>(null) // 内容节点信息
const isHorizontal = computed(() => props.direction === 'horizontal')
const isVertical = computed(() => props.direction === 'vertical')
const transitionState = reactive<CSSProperties>({
transitionProperty: 'unset',
transitionDelay: 'unset',
transitionDuration: 'unset',
transform: 'none',
transitionTimingFunction: 'linear'
})
const animation = computed(() => {
return objToStyle(transitionState)
})
const rootStyle = computed(() => {
const style: CSSProperties = {}
if (isDef(props.color)) {
Expand Down Expand Up @@ -79,28 +91,66 @@ const noticeBarClass = computed(() => {
const { proxy } = getCurrentInstance() as any
watch(
[() => props.text],
() => props.text,
() => {
nextTick(() => scroll())
reset()
},
{ deep: true, immediate: true }
{ deep: true }
)
onMounted(() => {
startTransition()
// #ifdef APP-PLUS
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const currentWebview = currentPage.$getAppWebview!()
currentWebview.addEventListener('hide', () => {
stopTransition()
})
currentWebview.addEventListener('show', () => {
startTransition()
})
// #endif
})
onActivated(() => {
startTransition()
})
onDeactivated(() => {
stopTransition()
})
function reset() {
stopTransition()
startTransition()
}
function startTransition() {
nextTick(() => scroll())
}
function stopTransition() {
transitionState.transitionProperty = 'unset'
transitionState.transitionDelay = 'unset'
transitionState.transitionDuration = 'unset'
transitionState.transform = 'none'
transitionState.transitionTimingFunction = 'linear'
currentIndex.value = 0
verticalIndex.value = 0
}
function handleClose() {
show.value = false
emit('close')
}
function initAnimation({ duration, delay, translate }: { duration: number; delay: number; translate: number }) {
const style: CSSProperties = {
transitionProperty: 'all',
transitionDelay: `${delay}s`,
transitionDuration: `${duration}s`,
transform: `${props.direction === 'vertical' ? 'translateY' : 'translateX'}(${translate}px)`,
transitionTimingFunction: 'linear'
}
return objToStyle(style)
function setTransition({ duration, delay, translate }: { duration: number; delay: number; translate: number }) {
transitionState.transitionProperty = 'all'
transitionState.transitionDelay = `${delay}s`
transitionState.transitionDuration = `${duration}s`
transitionState.transform = `${props.direction === 'vertical' ? 'translateY' : 'translateX'}(${translate}px)`
transitionState.transitionTimingFunction = 'linear'
}
function queryRect() {
Expand All @@ -109,30 +159,31 @@ function queryRect() {
async function verticalAnimate(height: number) {
const translate = -(height / (textArray.value.length + 1)) * (currentIndex.value + 1)
animation.value = initAnimation({
setTransition({
duration: height / (textArray.value.length + 1) / props.speed,
delay: props.delay,
translate
})
}
async function scroll() {
const [wrapRect, contentRect] = await queryRect()
if (!wrapRect.width || !contentRect.width || !contentRect.height) return
wrapWidth.value = wrapRect.width
const [wRect, cRect] = await queryRect()
if (!wRect.width || !cRect.width || !cRect.height) return
wrapRect.value = wRect
contentRect.value = cRect
wrapWidth.value = wRect.width
if (isHorizontal.value) {
if (props.scrollable) {
animation.value = initAnimation({
duration: contentRect.width / props.speed,
setTransition({
duration: cRect.width / props.speed,
delay: props.delay,
translate: -contentRect.width
translate: -cRect.width
})
}
} else {
if (textArray.value.length > 1) {
verticalAnimate(contentRect.height)
verticalAnimate(cRect.height)
}
}
}
Expand All @@ -148,15 +199,15 @@ function next() {
function animationEnd() {
if (isHorizontal.value) {
animation.value = initAnimation({
setTransition({
duration: 0,
delay: 0,
translate: wrapWidth.value + 1 // +1容错空间,防止露出来一丢丢
translate: wrapWidth.value + 1
})
} else {
if (++verticalIndex.value >= textArray.value.length) {
verticalIndex.value = 0
animation.value = initAnimation({
setTransition({
duration: 0,
delay: 0,
translate: 0
Expand All @@ -168,18 +219,25 @@ function animationEnd() {
next() // 更换下一条文本
nextTick(async () => {
// 因为文本会发生变化,所以每一次都需要查询
const [_, contentRect] = await queryRect()
if (!contentRect.width || !contentRect.height) return
try {
const [wRect, cRect] = await queryRect()
wrapRect.value = wRect
contentRect.value = cRect
wrapWidth.value = wRect.width || 0
} catch (error) {
// console.error(error)
}
if (!contentRect.value || !contentRect.value.width || !contentRect.value.height) return
if (isHorizontal.value) {
animation.value = initAnimation({
duration: (wrapWidth.value + contentRect.width) / props.speed,
setTransition({
duration: (wrapWidth.value + contentRect.value.width) / props.speed,
delay: props.delay,
translate: -contentRect.width
translate: -contentRect.value.width
})
} else {
verticalAnimate(contentRect.height)
verticalAnimate(contentRect.value.height)
}
})
Expand All @@ -199,6 +257,8 @@ function handleClick() {
}
emit('click', result)
}
defineExpose<NoticeBarExpose>({ reset })
</script>

<style lang="scss" scoped>
Expand Down

0 comments on commit 7584ac2

Please sign in to comment.