动画
看名字我们就知道这个 API 和动画有关系。为了便于理解 requestAnimationFrame ,可以把它和 setTimeout 来做类比,假如要使用 setTimeout 来实现一个进度条的动画效果,那么代码可以像下面这样写:
<div class="box" style="width: 0;">0%</div>
.box { line-height: 24px; background: red; }
box.addEventListener('click', function() {
let timer = setTimeout(function fn() {
// 行内样式才可以通过 style.width 获取到
box.style.width = parseInt(box.style.width) + 5 + 'px'
box.innerText = parseInt(box.style.width) / 2 + '%'
timer = setTimeout(fn, 17)
if (parseInt(box.style.width) >= 200) {
clearTimeout(timer)
}
}, 17)
})
我们可以使用 requestAnimationFrame 来改写,其区别主要在于不需要提供延迟参数了,浏览器自身会根据自己的渲染机制来调用此函数。
代码如下:
box.addEventListener('click', function() {
let timer = requestAnimationFrame(function fn() {
box.style.width = parseInt(box.style.width) + 5 + 'px'
box.innerText = parseInt(box.style.width) / 2 + '%'
timer = requestAnimationFrame(fn)
if (parseInt(box.style.width) >= 200) {
cancelAnimationFrame(timer)
}
})
})
关于回调的参数
使用 requestAnimationFrame 时,接收一个回调,回调的参数是一个毫秒值,表示下次重绘的时间。
MDN 上的范例很好地解释了该如何灵活使用该参数:
const element = document.getElementById('some-element-you-want-to-animate');
let start;
function step(timestamp) {
if (start === undefined)
start = timestamp;
const elapsed = timestamp - start;
//这里使用`Math.min()`确保元素刚好停在200px的位置。
element.style.transform = 'translateX(' + Math.min(0.1 * elapsed, 200) + 'px)';
if (elapsed < 2000) { // 在两秒后停止动画
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
参考链接
- requestAnimationFrame 到底解决的是什么问题?
- 张鑫旭 requestAnimationFrame
- MDN requestAnimationFrame
- 《JavaScript高级程序设计》第四版 第18章 动画与 Canvas 图形