requestAnimationFrame是什么?
在浏览器动画程序中,我们通常使用一个定时器来循环每隔几毫秒移动目标物体一次,来让它动起来。如今有一个好消息,浏览器开发商们决定:“嗨,为什么我们不在浏览器里提供这样一个API呢,这样一来我们可以为用户优化他们的动画。”所以,这个requestAnimationFrame()
函数就是针对动画效果的API,你可以把它用在DOM上的风格变化或画布动画或WebGL中。
使用requestAnimationFrame有什么好处?
浏览器可以优化并行的动画动作,更合理的重新排列动作序列,并把能够合并的动作放在一个渲染周期内完成,从而呈现出更流畅的动画效果。比如,通过requestAnimationFrame()
,JS动画能够和CSS动画/变换或SVG SMIL动画同步发生。另外,如果在一个浏览器标签页里运行一个动画,当这个标签页不可见时,浏览器会暂停它,这会减少CPU,内存的压力,节省电池电量。
requestAnimationFrame的用法
简单的兼容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// shim layer with setTimeout fallback window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); }; })(); // usage: // instead of setInterval(render, 16) .... (function animloop(){ requestAnimFrame(animloop); render(); })(); // place the rAF *before* the render() to assure as close to // 60fps with the setTimeout fallback. |
由于谷歌火狐浏览器为requestAnimationFrame 提供了支持,我相信以后 也会有o(opera)ms(IE)等支持 ?于是我们的函数就变成了这样
1 2 3 4 5 6 7 8 9 10 |
window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(/* function */ callback, /* DOMElement */ element){ window.setTimeout(callback, 1000 / 60); }; })(); |
对requestAnimationFrame更牢靠的封装
Opera浏览器的技术师Erik M?ller 把这个函数进行了封装,使得它能更好的兼容各种浏览器。你可以读一读这篇文章,但基本上他的代码就是判断使用4ms
还是16ms
的延迟,来最佳匹配60fps。下面就是这段代码,你可以使用它,但请注意,这段代码里使用的是标准函数,我给它加上了兼容各种浏览器引擎前缀。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
(function() { var lastTime = 0; var vendors = ['webkit', 'moz']; 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 API
1 2 3 |
window.requestAnimationFrame(function(/* time */ time){ // time ~= +new Date // the unix time }); |
下面附上 2 个 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 |
// requestAnim shim layer by Paul Irish window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(/* function */ callback, /* DOMElement */ element){ window.setTimeout(callback, 1000 / 60); }; })(); // example code from mr doob : http://mrdoob.com/lab/javascript/requestanimationframe/ var canvas, context, toggle; init(); animate(); function init() { canvas = document.createElement( 'canvas' ); canvas.width = 512; canvas.height = 512; context = canvas.getContext( '2d' ); document.body.appendChild( canvas ); } function animate() { requestAnimFrame( animate ); draw(); } function draw() { var time = new Date().getTime() * 0.002; var x = Math.sin( time ) * 192 + 256; var y = Math.cos( time * 0.9 ) * 192 + 256; toggle = !toggle; context.fillStyle = toggle ? 'rgb(200,200,20)' : 'rgb(20,20,200)'; context.beginPath(); context.arc( x, y, 10, 0, Math.PI * 2, true ); context.closePath(); context.fill(); } |
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 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>dom Framework</title> <style> #anim { position:absolute; left:0px; width:150px; height:150px; background: blue; font-size: larger; color: white; border-radius: 10px; padding: 1em; } </style> </head> <body> <div id="anim">Click here to start animation</div> <script> // shim layer with setTimeout fallback window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element){ window.setTimeout(callback, 1000 / 60); }; })(); var elem = document.getElementById("anim"); var startTime = undefined; function render(time) { if (time === undefined) time =new Date()-0; if (startTime === undefined) startTime = time; elem.style.left = ((time - startTime)/10 % 500) + "px"; } elem.onclick = function() { (function animloop(){ render(); requestAnimFrame(animloop, elem);//elem没有用 })(); }; </script> </body> </html> |
各种浏览器对requestAnimationFrame的支持情况
谷歌浏览器,火狐浏览器,IE10+都实现了这个函数,即使你的浏览器很古老,上面的对requestAnimationFrame封装也能让这个方法在IE8/9上不出错。
Android 貌似要4.2 以上才能支持 ,要注意
相关文章
http://www.zhangxinxu.com/study/201309/requestanimationframe-tween-easeoutbounce.html? DEMO