requestAnimationFrame,Web中写动画的另一种选择

 原文:https://www.cnblogs.com/Wayou/p/requestAnimationFrame.html

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的更多相关文章

  1. 利用requestAnimationFrame和Tween算法实现兼容所有浏览器的运动动画,直接秒杀Css3动画

    以下贴出Tween的代码: /* * Tween.js * t: current time(当前时间): * b: beginning value(初始值): * c: change in value ...

  2. 云端js动态效果

    效果图: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  3. JS中EventLoop、宏任务与微任务的个人理解

    为什么要EventLoop? JS 作为浏览器脚本语言,为了避免复杂的同步问题(例如用户操作事件以及操作DOM),这就决定了被设计成单线程语言,而且也将会一直保持是单线程的.而在单线程中若是遇到了耗时 ...

  4. htm5实现视差动画

    requestAnimationFrame.js window.requestAnimFrame = (function() { return window.requestAnimationFrame ...

  5. jQuery仿天猫完美加入购物车

    转载自:http://www.iteye.com/topic/1138064 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transiti ...

  6. Html5 小游戏 俄罗斯方块

    导言 在一个风和日丽的一天,看完了疯狂HTML 5+CSS 3+JavaScript讲义,跟着做了书里最后一章的俄罗斯方块小游戏,并做了一些改进,作为自己前端学习的第一站. 游戏效果: 制作思路 因为 ...

  7. 跟着whatwg看一遍事件循环

    前言 对于单线程来说,事件循环可以说是重中之重了,它为任务分配不同的优先级,井然有序的调度.让js解析,用户交互,页面渲染等互不冲突,各司其职. 我们书写的代码无时无刻都在和事件循环打交道,要想写出更 ...

  8. angular页面

    <!DOCTYPE html><!--[if lt IE 9]> <html lang="zh" xmlns:ng="http://angu ...

  9. 性能更好的js动画实现方式——requestAnimationFrame

    用js来实现动画,我们一般是借助setTimeout或setInterval这两个函数,css3动画出来后,我们又可以使用css3来实现动画了,而且性能和流畅度也得到了很大的提升.但是css3动画还是 ...

随机推荐

  1. 用Python从零开始实现K近邻算法

    KNN算法的定义: KNN通过测量不同样本的特征值之间的距离进行分类.它的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别.K通 ...

  2. eclipse mars 4.5.1 自定义工具栏

    window>>perspective>>Customize Perspective

  3. JSP_运维_JSP项目部署到server(适合0经验新手)

    实战:真正server端部署jsp项目经验总结与记录(完整过程从0到10适合对server端部署0经验新手) jsp+tomcat+mysql项目部署到真正server; servermysql安装; ...

  4. [Linux实用工具]munin-node插件配置和插件编写

    前面介绍了2篇munin使用的相关文章: [Linux实用工具]Linux监控工具munin的安装和配置 [Linux实用工具]Linux监控工具munin的展示(Nginx)   这次介绍一下mun ...

  5. [Linux基础环境/软件]Linux下安装resin web服务器(涉及gcc、jdk环境部署)

    由于Ubuntu自带是没有jdk和gcc编译器的,而安装resin需要C编译器和jdk的支持,而且resin本身是java写的.另外我本身的网站是zip打包的,所以linux也要安装了gcc.jdk. ...

  6. Domain应用之 根据某个Many2one的对象的 X2many对象 过滤

    如果两者都是many2one类型的对象,过滤非常简单,在xml中添加domain过滤即可,比如 国家.省市之间的联动关系. 如果想要根据某个对象的X2many类型的字段进行过滤该如何去做呢? 答案是利 ...

  7. javascript 60行编写的俄罗斯方块游戏

    转自 http://***/share/1759652641295360.htm <!doctype html><html><head></head>& ...

  8. 在VMware中为CentOS配置静态ip并可访问网络

    在VMware中为CentOS配置静态ip并可访问网络-windows下的VMware  首先确保虚拟网卡(VMware Network Adapter VMnet8)是开启的,然后在windows的 ...

  9. input 模糊搜索

    <html> <head> <title>test</title> <script type="text/javascript" ...

  10. git 通过nginx 无法clone

    git服务器架设在内网,通过nginx做反向代理后如果公网质量差的话部分项目无法clone,报错: error: RPC failed; result=18, HTTP code = 200B | 3 ...