用requestanimationframe实现倒计时可避免setinterval的时间漂移和丢帧,通过performance.now()计算真实经过时间确定剩余秒数,配合插值过渡与及时取消动画确保流畅精准。

用 requestAnimationFrame 实现数字倒计时动效,核心是**避免 setInterval 的时间漂移和丢帧问题**,让每一帧都精准对齐浏览器刷新节奏,从而获得真正流畅的视觉效果。关键不在于“每秒更新多少次”,而在于“每次更新都发生在下一帧开始时”。
用 requestAnimationFrame 替代 setInterval
传统 setInterval(fn, 1000) 只是“尽量每秒执行一次”,但实际执行时机受 JS 主线程阻塞、任务队列延迟等影响,容易跳秒或卡顿。而 requestAnimationFrame 会把更新逻辑交给浏览器统一调度,保证动画与屏幕刷新率(通常是 60fps)同步。
注意:它本身不带时间间隔控制,需结合 performance.now() 手动计算已过去的时间。
倒计时逻辑要基于真实经过时间
不能靠帧数累加来推算秒数(比如“执行了 60 帧就减 1 秒”),因为帧率可能波动。正确做法是记录起始时间,在每一帧中读取当前时间戳,用差值计算剩余秒数:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 启动时调用
performance.now()记录startTime - 在 rAF 回调中再次调用
performance.now()得到currentTime - 用
totalDuration - (currentTime - startTime) / 1000算出剩余秒数(单位:秒) - 向下取整得到整秒数,再格式化为两位数字(如
String(Math.floor(seconds)).padStart(2, '0'))
数字变化要加缓动过渡(可选但推荐)
直接整秒跳变不够自然。可以对“当前显示数字”做插值过渡:比如从 5.00 过渡到 4.00,中间几帧显示 4.75、4.50、4.25……这样视觉更顺滑。
实现方式:维护一个 currentDisplay 浮点数,每帧按比例向目标值靠近(例如使用 lerp 或简单乘系数);同时用 Math.floor(currentDisplay) 渲染整数部分,小数部分可隐藏或用于微调动画。
记得及时终止动画循环
倒计时归零后,必须停止调用 requestAnimationFrame,否则会持续占用资源。常见做法:
- 在回调开头判断剩余时间 ≤ 0,如果是,不继续请求下一帧,并触发完成回调
- 保存上一次
requestAnimationFrame返回的 ID,用cancelAnimationFrame(id)显式清除(尤其在中途暂停/重置时)
不复杂但容易忽略:确保 DOM 更新(如修改 innerText)放在 rAF 回调内,且尽量轻量;避免在其中触发强制重排或大量计算。倒计时动效的流畅感,来自节奏可控 + 更新及时 + 清理到位。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










