js requestAnimationFrame
requestAnimationFrame,Web中写动画的另一种选择
HTML5/CSS3时代,我们要在web里做动画选择其实已经很多了:
你可以用CSS3的animattion+keyframes;
你也可以用css3的transition;
你还可以用通过在canvas上作图来实现动画,也可以借助jQuery动画相关的API方便地实现;
当然最原始的你还可以使用window.setTimout()或者window.setInterval()通过不断更新元素的状态位置等来实现动画,前提是画面的更新频率要达到每秒60次才能让肉眼看到流畅的动画效果。
现在又多了一种实现动画的方案,那就是还在草案当中的window.requestAnimationFrame()方法。
初识requestAnimationFrame
来看MDN上对其给出的诠释:
The window.requestAnimationFrame() method tells the browser that you wish to perform an animation and requests that the browser call a specified function to update an animation before the next repaint. The method takes as an argument a callback to be invoked before the repaint.
window.requestAnimationFrame() 将告知浏览器你马上要开始动画效果了,后者需要在下次动画前调用相应方法来更新画面。这个方法就是传递给window.requestAnimationFrame()的回调函数。
也可这个方法原理其实也就跟setTimeout/setInterval差不多,通过递归调用同一方法来不断更新画面以达到动起来的效果,但它优于setTimeout/setInterval的地方在于它是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销。
基本语法
可以直接调用,也可以通过window来调用,接收一个函数作为回调,返回一个ID值,通过把这个ID值传给window.cancelAnimationFrame()可以取消该次动画。
requestAnimationFrame(callback)//callback为回调函数
一个简单的例子
模拟一个进度条动画,初始div宽度为1px,在step函数中将进度加1然后再更新到div宽度上,在进度达到100之前,一直重复这一过程。
为了演示方便加了一个运行按钮(看不到例子请刷新)。
<div id="test" style="width:1px;height:17px;background:#0f0;">0%</div>
<input type="button" value="Run" id="run"/>

window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
var start = null;
var ele = document.getElementById("test");
var progress = 0; function step(timestamp) {
progress += 1;
ele.style.width = progress + "%";
ele.innerHTML=progress + "%";
if (progress < 100) {
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
document.getElementById("run").addEventListener("click", function() {
ele.style.width = "1px";
progress = 0;
requestAnimationFrame(step);
}, false);

浏览器支持情况
既然还是草案状态下引入的一个功能,在使用全我们就需要关心一下各浏览器对它的支持情况了。就目前来说,主流现代浏览器都对它提供了支持,请看下图:
|
|
|
|
|
|
|
31+ |
26+ |
10+ |
19+ |
6+ |
更为具体的浏览器兼容性可以在这里看到。
Polyfill
Polyfill就是垫片,按发明这个词的人的原话来说,它就是一段这样的代码,让浏览器原生地支持我们期望使用的一些API。
就比如这里的requestAnimationFrame,在看到了上面的浏览器支持情况后,你就知道了比上面列出的浏览器版本老的就不支持该方法,但为了让代码能够有更好的浏览器兼容性在老机器上也能运行不报错,我们可以写一些代码让浏览器在不支持requestAnimationFrame的情况下使用window.setTimeout(),这是一种回退(fallback)到过去的方法。
这样一来,就可以通俗一点的理解polyfill了,它就是备胎。
下面是由Paul Irish及其他贡献者放在GitHub Gist上的代码片段,用于在浏览器不支持requestAnimationFrame情况下的回退,回退到使用setTmeout的情况。当然,如果你确定代码是工作在现代浏览器中,下面的代码是不必的。

// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());

上面代码作用有二,一是把各浏览器前缀进行统一,二是在浏览器没有requestAnimationFrame方法时将其指向setTimeout方法。
提到备胎代码呢,这里多说一句,在CSS代码中,我们也经常使用这种回退的技巧,即对同一条CSS规则,编写多条以不同浏览器前缀开头代码,或者编写一条备用样式。
下面是一个CSS中的备胎代码的例子:
div {
background: rgb(0, 0, 0); /* fallback */
background: rgba(0, 0, 0, 0.5);
}
代码中设置div背景为黑色带50%的透明度,但IE9-的浏览器是不支持rbga格式的颜色的,所以浏览器会回退到上一条CSS规则应用rgb颜色。
Reference:
1. article about rAF from css tricks: http://css-tricks.com/using-requestanimationframe/
2. article about rAF from Paul Irish:http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
3. what is polyfill http://remysharp.com/2010/10/08/what-is-a-polyfill/
js requestAnimationFrame的更多相关文章
- 利用requestAnimationFrame和Tween算法实现兼容所有浏览器的运动动画,直接秒杀Css3动画
以下贴出Tween的代码: /* * Tween.js * t: current time(当前时间): * b: beginning value(初始值): * c: change in value ...
- 云端js动态效果
效果图: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...
- JS中EventLoop、宏任务与微任务的个人理解
为什么要EventLoop? JS 作为浏览器脚本语言,为了避免复杂的同步问题(例如用户操作事件以及操作DOM),这就决定了被设计成单线程语言,而且也将会一直保持是单线程的.而在单线程中若是遇到了耗时 ...
- htm5实现视差动画
requestAnimationFrame.js window.requestAnimFrame = (function() { return window.requestAnimationFrame ...
- jQuery仿天猫完美加入购物车
转载自:http://www.iteye.com/topic/1138064 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transiti ...
- Html5 小游戏 俄罗斯方块
导言 在一个风和日丽的一天,看完了疯狂HTML 5+CSS 3+JavaScript讲义,跟着做了书里最后一章的俄罗斯方块小游戏,并做了一些改进,作为自己前端学习的第一站. 游戏效果: 制作思路 因为 ...
- 跟着whatwg看一遍事件循环
前言 对于单线程来说,事件循环可以说是重中之重了,它为任务分配不同的优先级,井然有序的调度.让js解析,用户交互,页面渲染等互不冲突,各司其职. 我们书写的代码无时无刻都在和事件循环打交道,要想写出更 ...
- angular页面
<!DOCTYPE html><!--[if lt IE 9]> <html lang="zh" xmlns:ng="http://angu ...
- 性能更好的js动画实现方式——requestAnimationFrame
用js来实现动画,我们一般是借助setTimeout或setInterval这两个函数,css3动画出来后,我们又可以使用css3来实现动画了,而且性能和流畅度也得到了很大的提升.但是css3动画还是 ...
随机推荐
- Python3将两个有序数组合并为一个有序数组
[本文出自天外归云的博客园] 第一种思路,把两个数组合为一个数组然后再排序,问题又回归到冒泡和快排了,没有用到两个数组的有序性.(不好) 第二种思路,循环比较两个有序数组头位元素的大小,并把头元素放到 ...
- 基于Keepalived实现LVS双主高可用集群
Reference: https://mp.weixin.qq.com/s?src=3×tamp=1512896424&ver=1&signature=L1C7us ...
- python -- numpy 基本数据类型,算术运算,组合,分割 函数
0 NumPy数组 NumPy数组:NumPy数组是一个多维数组对象,称为ndarray.其由两部分组成: 实际的数据 描述这些数据的元数据 NumPy数组属性: ndim(纬数,x,y 2),sha ...
- [mqtt]mqtt嵌入式移植
github eclipse paho source code: https://github.com/mqtt/mqtt.github.io/wiki/libraries STM32 mqtt移植: ...
- Bash Shell (十一)
[教程主题]:Bash Shell [课程录制]: 创E [主要内容] [1] Hello World! 几乎所有的讲解编程的书给读者的第一个例子都是 Hello World 程序,那么我们今天也就从 ...
- RavenDb学习(六)查询补充特性
.延迟加载 原来的查询方式如下: IEnumerable<User> users = session .Query<User>() .Where(x => x.Name ...
- session过期跳出irame
在登录页底部加入 <script type="text/javascript"> if (window != top) top.location.href = loca ...
- centos7下部署elasticSearch集群
OS:Centos7x虚拟机 1H2Gjdk:1.8elasticsearch:5.6.0 单节点配置请参考:centos7下elasticSearch安装配置 配置master节点 # 在配置文件的 ...
- python datetime和unix时间戳之间相互转换
python datetime和unix时间戳之间相互转换 1.代码: import time import datetime # ...
- 请教 JTable 里的单元格如何使得双击进入单元格后,单元格的内容处于全选中状态
http://bbs.csdn.net/topics/390195204 ———————————————————————————————————————— java 达人, 最近在开发一个 java ...




