如何操作动画_JavaScript中requestAnimationFrame的基本用法是什么

10次阅读

requestAnimationFrame 是浏览器原生动画API,按屏幕刷新率执行且自动暂停;与 setTimeout 不同,它需递归调用、基于时间戳计算位移、及时 cancel 以避免泄漏。

如何操作动画_JavaScript中requestAnimationFrame的基本用法是什么

requestAnimationFrame 是什么,和 setTimeout 有什么区别

requestAnimationFrame浏览器提供的用于驱动动画的原生 API,它不是定时器,而是告诉浏览器“你下次重绘前,帮我执行这个函数”。相比 setTimeoutsetInterval,它更省电、更顺滑、自动适配屏幕刷新率(通常是 60fps),且在标签页不可见时会自动暂停。

常见错误是把它当“更高级的 setTimeout”来用,比如写成 requestAnimationFrame(() => { /* 一次就完事 */ }) —— 这样只会执行一帧,根本动不起来。

怎么写一个持续运行的动画循环

真正能动起来的动画,必须在回调里**递归调用自己**。这是最常漏掉的关键点。

  • 每次回调执行完动画逻辑后,立刻再调一次 requestAnimationFrame(animate)
  • 用一个变量保存当前帧 ID,方便后续用 cancelAnimationFrame 停止
  • 不要在回调里直接写死时间步长(如 pos += 2),应基于上一帧时间戳计算真实经过毫秒数,避免丢帧导致速度漂移
let animationId = null; let lastTime = 0; 

function animate(timestamp) { if (!lastTime) lastTime = timestamp; const deltaTime = timestamp - lastTime; lastTime = timestamp;

// 示例:让元素每秒移动 100px const speed = 100; // px/s element.style.transform = translateX(${speed * deltaTime / 1000}px);

animationId = requestAnimationFrame(animate); }

animationId = requestAnimationFrame(animate);

立即学习Java免费学习笔记(深入)”;

什么时候该停止 requestAnimationFrame

不手动停止会导致内存泄漏和后台持续耗电,尤其在组件卸载、页面切换或用户暂停动画时。

  • 调用 cancelAnimationFrame(animationId) 即可中断当前排队中的帧
  • 务必确保 animationId 是你上次 requestAnimationFrame 返回的值,赋值时机不能错
  • react/vue 等框架中,要在 useEffect cleanupbeforeUnmount 钩子中调用取消逻辑
  • 如果动画依赖某个 dom 元素,而该元素已被移除,继续执行会报错,建议加一层存在性判断

兼容性和性能注意点

现代浏览器都支持 requestAnimationFrame,但 IE10+ 才有,且需要带前缀 webkitRequestAnimationFrame(已基本可忽略)。真正容易被忽略的是帧率控制与精度问题:

  • timestamp 参数是高精度时间(单位毫秒,小数点后三位),别用 date.now() 替代,后者精度低且不受浏览器节流影响
  • 动画逻辑尽量轻量,避免在帧回调里做 DOM 查询、样式重排(offsetTop)、复杂计算;批量读写分离(先读所有 offset,再统一写 style)
  • 若需固定帧率(如强制 30fps),不能靠 if (timestamp % 33 这类取模——它不准确;应记录上一次渲染时间,差值不够就跳过本次

动画不是写得越勤快越好,而是刚好卡在浏览器重绘节奏上。多一帧没用,少一帧就卡。

text=ZqhQzanResources