js中requestAnimationFrame()解读与使用示例
作者:OEC小胖胖
requestAnimationFrame()
是 JavaScript 中用于实现动画效果的一个重要方法。它告诉浏览器你想执行动画,并要求浏览器在下次重绘之前调用指定的回调函数来更新动画。相比传统的 setTimeout
和 setInterval
,requestAnimationFrame()
更加高效且能够提供更流畅的动画。
基本概念
1. 浏览器的重绘和回流
浏览器通过一个叫做“帧”的机制来渲染页面内容。一般来说,浏览器每秒会尝试绘制 60 帧(60FPS),每一帧都需要浏览器计算布局、样式,并把内容绘制到屏幕上。requestAnimationFrame()
是专门为此设计的,它会让你的动画代码在浏览器的重绘过程中执行,确保每次动画更新都与浏览器的刷新频率同步。
2. 效率和节能
requestAnimationFrame()
会根据显示器的刷新率来自动调节帧率,常见的刷新率是 60FPS。如果你的显示器是 60Hz,requestAnimationFrame()
每秒会回调约 60 次。如果浏览器窗口被最小化,或者切换到另一个标签页,requestAnimationFrame()
会暂停执行,减少CPU和GPU的负载。这和 setTimeout
、setInterval
不同,它们会一直执行,即使页面不可见。
使用方法
let start = null; function step(timestamp) { if (!start) start = timestamp; const progress = timestamp - start; // 更新动画的位置,这里是简单的例子,假设移动一个物体 const element = document.getElementById('box'); element.style.transform = `translateX(${Math.min(progress / 10, 200)}px)`; if (progress < 2000) { // 继续动画,直到经过2秒 requestAnimationFrame(step); } } requestAnimationFrame(step);
示例详解
1. 回调函数
requestAnimationFrame()
需要一个回调函数作为参数,这个回调函数会在浏览器准备好绘制下一帧时被调用。在上面的示例中,step
函数就是这个回调函数。
2. timestamp 参数
浏览器会为回调函数传递一个 timestamp
参数,表示当前被请求的动画帧开始时的时间戳。这个 timestamp
是以毫秒为单位的高精度时间,可以用来计算动画进行的时间差。
3. 递归调用
在 step
函数内部,我们通过 requestAnimationFrame()
自己调用自己,形成一个动画的递归循环。每一次调用 requestAnimationFrame(step)
,浏览器都会在下一帧时再次执行 step
函数。
4. 条件控制
为了停止动画,我们可以在递归调用时通过条件判断,比如在上面的例子中,我们通过 progress < 2000
来控制动画持续 2 秒。如果不加这个条件,动画会一直进行下去。
与 setTimeout 和 setInterval 的比较
function moveBoxWithSetTimeout() { let position = 0; const element = document.getElementById('box'); function update() { position += 5; element.style.transform = `translateX(${position}px)`; if (position < 200) { setTimeout(update, 1000 / 60); // 每秒60次更新 } } update(); } function moveBoxWithRequestAnimationFrame() { let position = 0; const element = document.getElementById('box'); function update() { position += 5; element.style.transform = `translateX(${position}px)`; if (position < 200) { requestAnimationFrame(update); } } requestAnimationFrame(update); }
区别:
时间控制:
setTimeout(update, 1000 / 60)
人为指定每秒60帧,但实际性能可能受限于浏览器、CPU 等,不一定精准。requestAnimationFrame()
由浏览器根据系统的负载来决定最佳帧率,并与显示器的刷新同步。
后台标签页处理:
setTimeout
和setInterval
在后台标签页或最小化时仍然运行,浪费资源。requestAnimationFrame()
会在页面不可见时暂停,节省资源。
流畅度:
setTimeout
和setInterval
由于无法和浏览器的重绘同步,容易导致卡顿、抖动。requestAnimationFrame()
能提供更加平滑的动画效果。
多个动画场景
你可以通过 requestAnimationFrame()
同时控制多个动画。只需要确保每个动画逻辑在回调函数中被正确处理。
let box1 = document.getElementById('box1'); let box2 = document.getElementById('box2'); let start = null; function animate(timestamp) { if (!start) start = timestamp; const progress = timestamp - start; box1.style.transform = `translateX(${Math.min(progress / 10, 200)}px)`; box2.style.transform = `translateY(${Math.min(progress / 20, 300)}px)`; if (progress < 2000) { requestAnimationFrame(animate); } } requestAnimationFrame(animate);
上面的代码演示了:
box1
向右移动,每 10 毫秒移动一个像素,直到移动 200 像素。box2
向下移动,每 20 毫秒移动一个像素,直到移动 300 像素。
多个元素的动画可以在同一个 requestAnimationFrame
回调中进行,这样它们会同步进行,保证帧率的一致性。
动画的取消
requestAnimationFrame()
返回一个唯一的整数 ID,代表该动画帧请求。可以使用 cancelAnimationFrame()
取消这个动画。
let animationId; function step(timestamp) { // 动画逻辑 if (progress < 2000) { animationId = requestAnimationFrame(step); } } // 开始动画 animationId = requestAnimationFrame(step); // 取消动画 cancelAnimationFrame(animationId);
总结
- 同步与浏览器刷新频率:
requestAnimationFrame()
是与显示器的刷新率同步的动画方法,通常会以 60FPS 执行。 - 高效与节能:在页面不可见时,
requestAnimationFrame()
会暂停执行,避免不必要的计算。 - 流畅的动画体验:由于它与浏览器的重绘同步,能带来更加流畅的动画效果。
通过掌握 requestAnimationFrame()
,你可以更轻松地创建流畅且高效的动画效果,它是现代 Web 动画开发的核心工具之一。
到此这篇关于js中requestAnimationFrame()解读与使用示例的文章就介绍到这了,更多相关js requestAnimationFrame()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!