fix: 首页滚动条改为恒速并补移动端拖动

This commit is contained in:
2026-09-13 19:06:38 +08:00
parent 1254e3d5d0
commit cc4c20e77b
4 changed files with 587 additions and 25 deletions
+117
View File
@@ -0,0 +1,117 @@
import { describe, it, expect } from 'vitest'
import {
BASE_SPEED_PX_PER_SEC,
MAX_REPEAT_COUNT,
MAX_SPEED_PX_PER_SEC,
MIN_REPEAT_COUNT,
MIN_SPEED_PX_PER_SEC,
NARROW_SPEED_FACTOR,
clampAutoScrollTime,
getRepeatCount,
getScrollSpeedPxPerSec,
measureAutoScroll,
pxToTimeOffset,
} from '@/utils/autoScroll'
const DESKTOP = 1440
describe('getScrollSpeedPxPerSec', () => {
it('桌面端使用基准速度', () => {
expect(getScrollSpeedPxPerSec(DESKTOP)).toBe(BASE_SPEED_PX_PER_SEC)
})
it('正好 768px 属于手机端,769px 回到桌面速度', () => {
expect(getScrollSpeedPxPerSec(768)).toBeCloseTo(BASE_SPEED_PX_PER_SEC * NARROW_SPEED_FACTOR)
expect(getScrollSpeedPxPerSec(769)).toBe(BASE_SPEED_PX_PER_SEC)
})
it('手机端是桌面速度的固定倍数', () => {
const narrow = getScrollSpeedPxPerSec(375)
expect(narrow).toBeCloseTo(BASE_SPEED_PX_PER_SEC * NARROW_SPEED_FACTOR)
expect(narrow).toBeLessThan(getScrollSpeedPxPerSec(DESKTOP))
})
it('桌面速度始终夹在上下限内', () => {
;[0, 769, 1024, 1440, 2560].forEach(width => {
const speed = getScrollSpeedPxPerSec(width)
expect(speed).toBeGreaterThanOrEqual(MIN_SPEED_PX_PER_SEC)
expect(speed).toBeLessThanOrEqual(MAX_SPEED_PX_PER_SEC)
})
})
})
describe('measureAutoScroll', () => {
it('一轮距离为单份内容宽度,时长由恒速换算', () => {
// 单份 2000px60px/s → 33.3s
const metrics = measureAutoScroll(2000, DESKTOP)
expect(metrics).not.toBeNull()
expect(metrics!.loopWidth).toBe(2000)
expect(metrics!.speed).toBe(BASE_SPEED_PX_PER_SEC)
expect(metrics!.duration).toBeCloseTo((2000 / BASE_SPEED_PX_PER_SEC) * 1000)
})
it('速度恒定:内容量翻倍只改变时长,不改变速度', () => {
const few = measureAutoScroll(2000, DESKTOP)!
const many = measureAutoScroll(20000, DESKTOP)!
expect(few.speed).toBe(many.speed)
expect(many.duration / few.duration).toBeCloseTo(10)
})
it('内容为空或宽度异常时返回 null', () => {
expect(measureAutoScroll(0, DESKTOP)).toBeNull()
expect(measureAutoScroll(-100, DESKTOP)).toBeNull()
expect(measureAutoScroll(Number.NaN, DESKTOP)).toBeNull()
})
})
describe('getRepeatCount', () => {
it('内容再多也用最少两份', () => {
expect(getRepeatCount(5000, 1000)).toBe(MIN_REPEAT_COUNT)
})
it('内容比轨道窄时补足到能铺满并预留衔接份', () => {
// 单份 300px、轨道 1000pxceil(1000/300)+1 = 5
expect(getRepeatCount(300, 1000)).toBe(5)
// 刚好铺满也要多一份用于衔接
expect(getRepeatCount(1000, 1000)).toBe(2)
})
it('份数不超过上限', () => {
expect(getRepeatCount(1, 100000)).toBe(MAX_REPEAT_COUNT)
})
it('宽度非法时回退到最少份数', () => {
expect(getRepeatCount(0, 1000)).toBe(MIN_REPEAT_COUNT)
expect(getRepeatCount(Number.NaN, 1000)).toBe(MIN_REPEAT_COUNT)
expect(getRepeatCount(300, 0)).toBe(MIN_REPEAT_COUNT)
})
it('measureAutoScroll 会带上份数', () => {
expect(measureAutoScroll(300, 1000)!.repeatCount).toBe(5)
})
})
describe('pxToTimeOffset', () => {
it('按速度把位移换算成时间', () => {
expect(pxToTimeOffset(BASE_SPEED_PX_PER_SEC, BASE_SPEED_PX_PER_SEC)).toBe(1000)
expect(pxToTimeOffset(30, 60)).toBe(500)
})
it('速度为 0 或参数非法时返回 0', () => {
expect(pxToTimeOffset(100, 0)).toBe(0)
expect(pxToTimeOffset(Number.NaN, 60)).toBe(0)
})
})
describe('clampAutoScrollTime', () => {
it('夹在 0 与一轮时长之间', () => {
expect(clampAutoScrollTime(-500, 1000)).toBe(0)
expect(clampAutoScrollTime(1500, 1000)).toBe(1000)
expect(clampAutoScrollTime(400, 1000)).toBe(400)
})
it('参数非法时归零', () => {
expect(clampAutoScrollTime(Number.NaN, 1000)).toBe(0)
expect(clampAutoScrollTime(100, 0)).toBe(0)
})
})