requestAnimationFrame()方法
window.requestAnimationFrame() 全局函数用于请求浏览器调用指定的回调函数以在下次重绘渲染之前更新动画。
requestAnimationFrame() 方法语法:window.requestAnimationFrame(callback);
参 数:callback
告诉浏览器下一次渲染之前需要调用的函数,而通常显示器的刷新频率是 60Hz,即每秒重绘 60次,所以只要在回调函数中继续调用 requestAnimationFrame(callback) 执行自己,就能达到约每秒执行 60 次回调函数。
返回值:
返回一个 long 整数值,即请求 ID,用于唯一标识回调列表中的条目,这是一个非零值,可以向window.cancelAnimationFrame(id) 传递此值以取消刷新回调请求。
浏览器兼容性:
电脑端 | 移动端 | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | Android webview | Chrome for Android | Edge Mobile | Firefox for Android | Opera for Android | iOS Safari | |
基本支持 | 支持:24 | 支持 | 支持:23 | 支持:10 | 支持:15 | 支持:6.1 | 支持 | 支持:25 | 支持 | 支持:23 | 支持:15 | 支持:7.1 |
返回值 | 支持:23 | 支持 | 支持:11 | 支持:10 | 支持:15 | 支持:6.1 | 支持 | 支持:25 | 支持 | 支持:14 | 支持:15 | 支持:6.1 |
计时器对比
JS 动画都是通过在很短的时间内不停的渲染/绘制元素做到的,所以计时器一直是 Javascript 动画的核心技术,所以动画的关键就是刷新的间隔时间。刷新间隔需要尽量短,这样才能动画效果显得平滑流畅,如流水等,同时刷新间隔又不能太短,这样才能确保浏览器有能力渲染动画。
大多数电脑显示器的刷新频率是 60Hz,即每秒重绘 60次,而大多数浏览器都会对重绘操作加以限制,从而不超过显示器的重绘频率,因为即使超过显示器的频率上限,用户体验也难有提升。因此平滑动画的最佳循环间隔是通常是 1000ms/60,约等于16.6ms
与 setTimeout 和 setInterval 不同,requestAnimationFrame 不需要程序员自己设置时间间隔。setTimeout 和 setInterval 的问题是精确度低。它们的内在运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器 UI 线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行。
requestAnimationFrame 采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。
requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。
requestAnimationFrame 对于隐藏或不可见元素,将不会进行重绘或回流,就意味着使用更少的 CPU、GPU 和内存使用量。
requestAnimationFrame 是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销。
编码示例
<script type="text/javascript">
/**意义就是请求浏览器在下一次渲染图像前执行里面的函数
* 而一般的显示器约每秒刷新60次,所以约 1000/60 = 16.66 毫米后会执行里面的回调函数
*/
var timer = requestAnimationFrame(function () {
console.log("1");//输出 1
});
</script>
<script type="module">
/**意义就是请求浏览器在下一次渲染图像前执行里面的函数
* 而一般的显示器约每秒刷新60次,所以约 1000/60 = 16.66 毫米后会执行里面的回调函数
*/
var timer = requestAnimationFrame(function () {
console.log("1");
});
/**因为上面需要在约 16.66毫米之后才执行回调函数,这里直接就取消了,所以上面的 1 不会再输出*/
cancelAnimationFrame(timer);
</script>
如上图所示动画效果代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.div1 {
width: 300px;
height: 200px;
background-color: #888888;
position: relative;
}
.div2 {
width: 200px;
height: 50px;
background-color: #122b40;
position: absolute;
left: calc(50% - 100px);
top: calc(50% - 25px);
/* 旋转元素,Internet Explorer 10、Firefox*/
transform: rotate(0deg);
/**浏览器兼容*/
/* Internet Explorer */
/*-ms-transform: rotate(45deg);*/
/* Firefox */
/*-moz-transform: rotate(45deg); */
/* Safari 和 Chrome */
/*-webkit-transform: rotate(45deg); */
/* Opera */
/*-o-transform: rotate(45deg); */
}
</style>
<!-- JQuery CDN-->
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<!-- ES6 JS-->
<script type="module">
/**rotateDeg:旋转的角度
* frameId:帧动画执行回调函数之前请求浏览器的
*/
var rotateDeg = 1;
var frameId = -1;
/**
* 旋转元素-动画效果
*/
var rotateImg = function () {
console.log(frameId);
/**设置元素 css 旋转属性,改变角度*/
$(".div2").css("transform", "rotate(" + rotateDeg + "deg)");
/**将角度加1度*/
rotateDeg += 1;
/**再次回调自己*/
frameId = requestAnimationFrame(rotateImg);
};
$(function () {
/**开始动画*/
$("#start").click(function () {
rotateImg();
});
/**结束动画*/
$("#stop").click(function () {
cancelAnimationFrame(frameId);
});
});
</script>
</head>
<body>
<div class="div1">
<div class="div2"></div>
</div>
<button id="start">开始动画</button>
<button id="stop">暂停动画</button>
</body>
</html>