一、概述
- 概念:帧动画,就是可以一帧一帧的执行动画
- 解决问题:解决了浏览器不知道
javascript
动画什么时候开始、不知道最佳循环间隔时间的问题。它是跟着浏览器的绘制走的,如果浏览器绘制间隔是16.7ms,它就按这个间隔绘制;如果浏览器绘制间隔是10ms, 它就按10ms绘制。这样就不会存在过度绘制的问题,动画不会丢帧
特点:
- 就算很多个
requestAnimationFrame()
要执行,浏览器只要通知一次就可以了。而setTimeout
是多个独立绘制。 - 一旦页面不出于当前页面(比如:页面最小化了),页面是不会进行重绘的,自然
requestAnimationFrame
也不会触发(因为没有通知)。页面绘制全部停止,资源高效利用
二、用法
requestAnimationFrame
是HTML5版本新增的API方法- 被绑定在window对象身上
- 接收一个回调函数作为参数
- 返回值是当前执行的唯一标志,用来清除这次执行(与计时器类似)
注意没有时间参数,因为会自动随着屏幕的刷新频率自动执行,所以最终语法为:
let myReq;
let i = 0;
function step(timestamp) {
console.log(i++);
myReq = window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
window.cancelAnimationFrame(myReq); // 清除方式
兼容性
1、requestAnimationFrame()的兼容性封装
由于mozRequestAnimationFrame()
是HTML5的新功能,目前各大浏览器的支持情况各异。如果希望代码具备更好的跨平台性,可以考虑使用下面的代码实现各平台兼容性:
if(!window.requestAnimationFrame) {
window.requestAnimationFrame = (window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
var self = this, start, finish;
return window.setTimeout(function() {
start = +new Date();
callback(start);
finish = +new Date();
self.timeout = 1000/60 - (finish - start);
}, self.timeout);
});
}
3、cancelRequestAnimFrame()的兼容性封装:
W3C也提供了cancelRequestAnimationFrame()
方法,用于取消回调函数。requestAnimationFrame()
方法会返回一个对象,用做标识回掉函数身份。若要取消回调函数的执行,可将其传给cancelRequestAnimationFrame()
window.cancelRequestAnimFrame = ( function() {
return window.cancelAnimationFrame ||
window.webkitCancelRequestAnimationFrame ||
window.mozCancelRequestAnimationFrame ||
window.oCancelRequestAnimationFrame ||
window.msCancelRequestAnimationFrame ||
clearTimeout;
} )();
三、 通过requestAnimationFrame
来实现定时器
function setInterval(callback, interval) {
let timer
const now = Date.now
let startTime = now()
let endTime = startTime
const loop = () => {
timer = window.requestAnimationFrame(loop)
endTime = now()
if (endTime - startTime >= interval) {
startTime = endTime = now()
callback(timer)
}
}
timer = window.requestAnimationFrame(loop)
return timer
}
let a = 0
setInterval(timer => {
console.log(1)
a++
if (a === 3) cancelAnimationFrame(timer)
}, 1000)