requestAnimationFrame实现动画

requestAnimationFramehtml5提供的一个专门用于请求动画的API,顾名思义就是请求动画帧。requestAnimationFrame采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。

requestAnimationFrame的优点

  • 采用系统时间间隔,保持最佳绘制效率,间隔时间相对精确,不会引起丢帧,不会卡断。而setTimeoutsetInterval时间间隔不精确。
  • requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般是大约每16.7ms执行一次
  • requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下或者页面被隐藏或最小化时,动画会自动暂停,有效节省了CPU开销,当页面被激活时,动画从上次暂停的地方继续执行。可解决使用setTimeout或setInterval定时器的轮播图可能存在的问题。
  • 使用setTimeout或setInterval实现的动画,当页面被隐藏或最小化时,setTimeout 仍然在后台执行动画任务,由于此时页面处于不可见或不可用状态,刷新动画是没有意义的,完全是浪费CPU资源,由于动画在后台执行在返回页面未刷新时,有时会看到轮播图快速执行多次。
  • 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量

如何使用requestAnimationFrame

requestAnimationFrame的用法与setTimeout很相似,只是不需要设置时间间隔而已。requestAnimationFrame使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数的执行。

1
2
3
4
5
// 定义requestAnimationFrame定时器
var timer = requestAnimationFrame(function(){})
console.log(timer) // 1
// cancelAnimationFrame 取消定时器
cancelAnimationFrame(timer) //控制台什么都不输出

兼容性处理

IE9及以下浏览器不支持该方法

1
2
3
4
5
6
7
8
window.requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ) {
window.setTimeout( callback, 1000 / 60 )
}
})();

requestAnimationFrame

简单使用案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#porgress {
display: block;
margin: 16px 0;
width: 400px;
height: 16px;
border-radius: 8px;
background-color:#ececf4;
display: flex;
overflow: hidden;
}
#porgress .inner{
width: 0px;
height: 16px;
border-radius: 8px;
font-size: 12px;
text-align: center;
background-image: linear-gradient(to right, #8575ff, #6bcdfe);
/* startColorstr表示起点的颜色,endColorstr 表示终点颜色。GradientType 表示渐变类型,0 为缺省值,表示垂直渐变,1 表示水平渐变 */
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#8575ff, endColorstr=#6bcdfe);/*IE9*/
}
</style>
</head>
<body>
<div id="porgress">
<div class="inner">0%</div>
</div>
<button id="btn">执行动画</button>
<script>
/* 当页面最小化 或 隐藏时 或者 切换页面处于未激活时
动画会自动暂停 重新激活 动画会从上次暂停的地方继续执行*/
var timer;
var startTime = 0
var endTime = 0
var n;
var inner = document.querySelector('.inner')
btn.onclick = function(){
n = 0;
inner.style.width = '0px'
cancelAniFrame && cancelAniFrame(timer)
startTime = new Date().getTime()
console.log(startTime, '动画开始时间')
timer = requestAnimFrame(step)
}
function step(){
if (parseInt(inner.style.width) < 400) {
inner.style.width = parseInt(inner.style.width) + 4 + 'px'
inner.innerHTML = parseInt(inner.style.width) / 4 + '%'
timer = requestAnimFrame(step)
n++
} else{
endTime = new Date().getTime()
console.log(endTime, '动画结束时间')
console.log(n, '动画执行次数') // 100
console.log((endTime - startTime)/n, '每次执行的时间')
// 16.7 每次可能有点差别但都是16.x毫秒 在ie中大约时15ms
cancelAniFrame && cancelAniFrame(timer)
}
}
window.requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame || function( callback ) {
window.setTimeout( callback, 1000 / 60 )
}
})();
window.cancelAniFrame = (function(){
return window.cancelAnimationFrame || window.mozCancelAnimationFrame
})();
</script>
</body>
</html>
-------------本文结束感谢您的阅读-------------
0%