数字滚动动画常见于数据大屏、计数器、统计面板。本文按「需求 -> 原理 -> 实现 -> 性能 -> 实战」的顺序,带你完成一个高性能、可复用、内存友好的 Vue 3 数字滚动组件。
设计一个数字滚动组件,要求:
数字滚动的本质是「逐位滚动」:
translateY 改变可视窗口中的数字N 的偏移量是 N * -100%例如显示数字 5:
0 ← translateY: 0%
1
2
3
4
5 ← translateY: -500% (当前显示)
6
7
8
9
理解这个映射关系后,再看代码会非常直接。
transform 做位移动画// 修改 margin 或 top 会触发布局重排
style.marginTop = value;
style.top = value;
// transform 更容易走 GPU 合成层,动画更稳定
:style="{ transform: `translateY(${value}%)` }"
// 字符串转数组,用于逐位显示
const displayedChars = computed(() => targetValue.value.split(""));
// 计算每一位的偏移距离
const getTranslateY = (char: string): string => {
if (char === ".") return "0";
const digit = parseInt(char, 10);
return digit * -100 + "%";
};
定时器未清理是常见内存泄漏来源,尤其在高频数据更新场景中。
// ❌ 问题代码
watch(
() => props.value,
() => {
setTimeout(() => updateValue(), 1000); // 快速更新时会堆积多个 timer
},
);
// ✅ 正确做法
let timerId: ReturnType<typeof setTimeout> | null = null;
const clearTimer = () => {
if (timerId) clearTimeout(timerId);
};
watch(
() => props.value,
() => {
clearTimer(); // 先清理旧 timer
timerId = setTimeout(() => updateValue(), 1000);
},
);
onUnmounted(() => clearTimer()); // 卸载时清理
// cubic-bezier(0.34, 1.56, 0.64, 1) 有轻微弹性回落效果
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
参数含义:
0.34, 1.56:前半段加速并略微超调0.64, 1:后半段回落并稳定停住NumberScroll.vue:可复用的高性能数字滚动组件。
技术栈:
关键特性:
| 实现方式 | FPS | 内存泄漏 | 响应性 |
|---|---|---|---|
| margin 修改 | 30-45 | 有 | ⚠️ 中等 |
| position 修改 | 45-55 | 有 | ⚠️ 中等 |
| transform | 55-60 | 无 | ✅ 优秀 |
完整交互式演示请访问 🎮 数字滚动动画试炼场。
你可以在试炼场中:
// 可以在前面加符号
const displayValue = value < 0 ? `-${Math.abs(value)}` : `${value}`;
// 可以通过 duration prop 自定义
<NumberScroll :value="num" :duration="500" />
const formatted = value.toLocaleString(); // 1,234,567
// 然后显示格式化后的字符串
相关资源:
(注:文档内容由 Copilot 生成)