diff --git a/src/packages/noticebar/__test__/noticebar.spec.tsx b/src/packages/noticebar/__test__/noticebar.spec.tsx
index 367e19a15e..521ce8e4ae 100644
--- a/src/packages/noticebar/__test__/noticebar.spec.tsx
+++ b/src/packages/noticebar/__test__/noticebar.spec.tsx
@@ -169,7 +169,7 @@ test('vertical test move', async () => {
await act(() => {
expect(
container.querySelector('.nut-noticebar-box-horseLamp-list')
- ).toHaveAttribute('style', 'transition: all 0.8s; margin-top: -30px;')
+ ).not.toHaveAttribute('style')
})
})
@@ -253,7 +253,6 @@ test('vertical container height calculation with children', async () => {
// 验证容器高度应该是 (childCount + 1) * height
// childCount = 4, height = 50, 所以期望高度是 (4 + 1) * 50 = 250px
const expectedHeight = `${(horseLamp1.length + 1) * height}px`
- console.log(wrapElement, 'wrapElement')
expect(wrapElement).toHaveStyle(`height: ${expectedHeight}`)
}
},
@@ -352,3 +351,123 @@ test('dynamic children update test', async () => {
})
})
})
+
+describe('NoticeBar Vertical Scrolling with refined timing logic', () => {
+ beforeEach(() => {
+ vi.useFakeTimers()
+ })
+
+ afterEach(() => {
+ vi.useRealTimers()
+ })
+
+ // 测试 list Prop 模式下的时间和动画
+ test('list mode: should correctly display items based on scrollList and style', async () => {
+ const listData = ['公告1', '公告2', '公告3']
+ const itemHeight = 30
+ const animationSpeed = 15
+ const calculatedAnimationTime = (30 / 15 / 4) * 1000
+ const pauseDuration = 2000
+
+ const { container } = render(
+
+ )
+
+ const listElement = container.querySelector(
+ '.nut-noticebar-box-horseLamp-list'
+ )
+ expect(listElement).toBeInTheDocument()
+ let items = listElement?.querySelectorAll(
+ '.nut-noticebar-box-horseLamp-list-item'
+ )
+
+ // 初始状态,显示第一项 "公告1"
+ expect(items?.[0]).toHaveTextContent('公告1')
+
+ // 第一次滚动
+ act(() => {
+ vi.advanceTimersByTime(pauseDuration + 1)
+ })
+ await waitFor(() => {
+ expect(listElement).toHaveStyle(`margin-top: -${itemHeight}px`)
+ expect(listElement).toHaveStyle(
+ `transition: all ${calculatedAnimationTime}ms`
+ )
+ })
+
+ // 动画结束并且开始下一轮
+ act(() => {
+ vi.advanceTimersByTime(calculatedAnimationTime - 1)
+ })
+ await waitFor(() => {
+ expect(listElement).not.toHaveStyle(`margin-top: -${itemHeight}px`)
+ items = listElement?.querySelectorAll(
+ '.nut-noticebar-box-horseLamp-list-item'
+ )
+ // 内部 scrollList.current 变为 ['公告2', '公告3', '公告1']
+ expect(items?.[0]).toHaveTextContent('公告2')
+ expect(items?.[1]).toHaveTextContent('公告3')
+ expect(items?.[2]).toHaveTextContent('公告1')
+ })
+ })
+
+ // 测试 children Prop 模式下的时间和动画
+ test('children mode: should use duration as pause, speed/height for animation', async () => {
+ const itemHeight = 30
+ const animationSpeed = 15
+ const calculatedAnimationTime = (30 / 15 / 4) * 1000
+ const pauseDuration = 2000
+
+ const { container } = render(
+
+ 公告1
+ 公告2
+ 公告3
+
+ )
+
+ const listElement = container.querySelector(
+ '.nut-noticebar-box-wrap'
+ )
+ expect(listElement).toBeInTheDocument()
+
+ // 第一次滚动
+ act(() => {
+ vi.advanceTimersByTime(pauseDuration + 1)
+ })
+
+ await waitFor(() => {
+ expect(listElement).toHaveStyle(
+ `transition-duration: ${calculatedAnimationTime}ms`
+ )
+ expect(listElement).toHaveStyle(
+ `transform: translate3D(0,-${itemHeight}px,0)`
+ )
+ })
+
+ // 开始下一轮滚动
+ act(() => {
+ vi.advanceTimersByTime(calculatedAnimationTime + pauseDuration)
+ })
+
+ await waitFor(() => {
+ expect(listElement).toHaveStyle(
+ `transition-duration: ${calculatedAnimationTime}ms`
+ )
+ expect(listElement).toHaveStyle(
+ `transform: translate3D(0,-${2 * itemHeight}px,0)`
+ )
+ })
+ })
+})
diff --git a/src/packages/noticebar/demos/h5/demo10.tsx b/src/packages/noticebar/demos/h5/demo10.tsx
index 646c5299c3..fbf3f6a8db 100644
--- a/src/packages/noticebar/demos/h5/demo10.tsx
+++ b/src/packages/noticebar/demos/h5/demo10.tsx
@@ -17,7 +17,7 @@ const Demo9 = () => {
direction="vertical"
height={50}
speed={10}
- duration={1000}
+ duration={3000}
closeable
onClose={() => {
console.log('close')
diff --git a/src/packages/noticebar/demos/h5/demo11.tsx b/src/packages/noticebar/demos/h5/demo11.tsx
index c6ab025834..3b0e8b7a93 100644
--- a/src/packages/noticebar/demos/h5/demo11.tsx
+++ b/src/packages/noticebar/demos/h5/demo11.tsx
@@ -16,7 +16,7 @@ const Demo10 = () => {
direction="vertical"
list={horseLamp1}
speed={10}
- duration={1000}
+ duration={3000}
onItemClick={(e, v) => {
console.log('onclick-custom', v)
}}
diff --git a/src/packages/noticebar/noticebar.taro.tsx b/src/packages/noticebar/noticebar.taro.tsx
index 1a36175485..5c2fd56869 100644
--- a/src/packages/noticebar/noticebar.taro.tsx
+++ b/src/packages/noticebar/noticebar.taro.tsx
@@ -190,26 +190,45 @@ export const NoticeBar: FunctionComponent<
}, 0)
}
+ // 滚动时间间隔
+ const scrollAnimationTimeMs = useMemo(() => {
+ if (Number(speed) <= 0 || Number(height) <= 0) return 0
+
+ // 用于计算时间(秒到毫秒,并处理 <1 秒的情况)
+ const calculateTimeInMs = (baseSeconds: number): number => {
+ if (baseSeconds < 1) {
+ // 例如 0.04s -> "0.0" -> 0ms. 0.05s -> "0.1" -> 100ms.
+ return Number(baseSeconds.toFixed(1)) * 1000
+ }
+ return Math.floor(baseSeconds) * 1000
+ }
+
+ // 尝试使用 /4 因子计算
+ const timeWithFactor4 = calculateTimeInMs(
+ Number(height) / Number(speed) / 4
+ )
+
+ if (timeWithFactor4 === 0) {
+ // 如果带 /4 因子的时间为0,则回退到不带 /4 因子的计算
+ return calculateTimeInMs(Number(height) / Number(speed))
+ }
+ return timeWithFactor4
+ }, [height, speed])
+
const startRollEasy = () => {
- showhorseLamp()
- const time =
- height / speed / 4 < 1
- ? Number((height / speed / 4).toFixed(1)) * 1000
- : ~~(height / speed / 4) * 1000
- const timerCurr = window.setInterval(showhorseLamp, time + Number(duration))
+ const timerCurr = window.setInterval(
+ showhorseLamp,
+ scrollAnimationTimeMs + Number(duration)
+ )
SetTimer(timerCurr)
}
const showhorseLamp = () => {
SetAnimate(true)
- const time =
- height / speed / 4 < 1
- ? Number((height / speed / 4).toFixed(1)) * 1000
- : ~~(height / speed / 4) * 1000
setTimeout(() => {
scrollList.current.push(scrollList.current[0])
scrollList.current.shift()
SetAnimate(false)
- }, time)
+ }, scrollAnimationTimeMs)
}
// 点击滚动单元
@@ -237,16 +256,8 @@ export const NoticeBar: FunctionComponent<
height: isVertical ? `${height}px` : '',
}
- const duringTime =
- height / speed / 4 < 1
- ? Number((height / speed / 4).toFixed(1))
- : ~~(height / speed / 4)
- const noDuring =
- height / speed < 1 ? (height / speed).toFixed(1) : ~~(height / speed)
const horseLampStyle = {
- transition: animate
- ? `all ${duringTime === 0 ? noDuring : duringTime}s`
- : '',
+ transition: animate ? `all ${scrollAnimationTimeMs}ms` : '',
marginTop: animate ? `-${height}px` : '',
}
@@ -306,7 +317,7 @@ export const NoticeBar: FunctionComponent<
next()
autoplay()
},
- Number(duration) + 100 * speed
+ Number(duration) + scrollAnimationTimeMs
)
}
@@ -375,7 +386,7 @@ export const NoticeBar: FunctionComponent<
moveOffset + Number(activeRef.current === childCount - 1 && val / 2)
target.style.transitionDuration = `${
- swiperRef.current.moving ? 0 : duration
+ swiperRef.current.moving ? 0 : scrollAnimationTimeMs
}ms`
target.style.height = `${Number(height) * (childCount + 1)}px`
target.style.transform = `translate3D(0,${_offset}px,0)`
diff --git a/src/packages/noticebar/noticebar.tsx b/src/packages/noticebar/noticebar.tsx
index a371e56538..0b95d0b415 100644
--- a/src/packages/noticebar/noticebar.tsx
+++ b/src/packages/noticebar/noticebar.tsx
@@ -187,17 +187,40 @@ export const NoticeBar: FunctionComponent<
SetAnimationClass('play-infinite')
}, 0)
}
+
// 滚动时间间隔
- const time =
- height / speed / 4 < 1
- ? Number((height / speed / 4).toFixed(1)) * 1000
- : ~~(height / speed / 4) * 1000
+ const scrollAnimationTimeMs = useMemo(() => {
+ if (Number(speed) <= 0 || Number(height) <= 0) return 0
+
+ // 用于计算时间(秒到毫秒,并处理 <1 秒的情况)
+ const calculateTimeInMs = (baseSeconds: number): number => {
+ if (baseSeconds < 1) {
+ // 例如 0.04s -> "0.0" -> 0ms. 0.05s -> "0.1" -> 100ms.
+ return Number(baseSeconds.toFixed(1)) * 1000
+ }
+ return Math.floor(baseSeconds) * 1000
+ }
+
+ // 尝试使用 /4 因子计算
+ const timeWithFactor4 = calculateTimeInMs(
+ Number(height) / Number(speed) / 4
+ )
+
+ if (timeWithFactor4 === 0) {
+ // 如果带 /4 因子的时间为0,则回退到不带 /4 因子的计算
+ return calculateTimeInMs(Number(height) / Number(speed))
+ }
+ return timeWithFactor4
+ }, [height, speed])
+
/**
* 滚动方式一,普通垂直滚动
*/
const startRollEasy = () => {
- showhorseLamp()
- const timerCurr = window.setInterval(showhorseLamp, time + Number(duration))
+ const timerCurr = window.setInterval(
+ showhorseLamp,
+ scrollAnimationTimeMs + Number(duration)
+ )
SetTimer(timerCurr)
}
@@ -207,7 +230,7 @@ export const NoticeBar: FunctionComponent<
scrollList.current.push(scrollList.current[0])
scrollList.current.shift()
SetAnimate(false)
- }, time)
+ }, scrollAnimationTimeMs)
}
// 点击滚动单元
@@ -235,16 +258,8 @@ export const NoticeBar: FunctionComponent<
height: isVertical ? `${height}px` : '',
}
- const duringTime =
- height / speed / 4 < 1
- ? Number((height / speed / 4).toFixed(1))
- : ~~(height / speed / 4)
- const noDuring =
- height / speed < 1 ? (height / speed).toFixed(1) : ~~(height / speed)
const horseLampStyle = {
- transition: animate
- ? `all ${duringTime === 0 ? noDuring : duringTime}s`
- : '',
+ transition: animate ? `all ${scrollAnimationTimeMs}ms` : '',
marginTop: animate ? `-${height}px` : '',
}
@@ -301,7 +316,7 @@ export const NoticeBar: FunctionComponent<
next()
autoplay()
},
- Number(duration) + 100 * speed
+ Number(duration) + scrollAnimationTimeMs
)
}
@@ -371,7 +386,7 @@ export const NoticeBar: FunctionComponent<
moveOffset + Number(activeRef.current === childCount - 1 && val / 2)
target.style.transitionDuration = `${
- swiperRef.current.moving ? 0 : duration
+ swiperRef.current.moving ? 0 : scrollAnimationTimeMs
}ms`
target.style.height = `${Number(height) * (childCount + 1)}px`
target.style.transform = `translate3D(0,${_offset}px,0)`