用js来实现动画,咱们通常是借助setTimeout或setInterval这两个函数,css3动画出来后,咱们又可使用css3来实现动画了,并且性能和流畅度也获得了很大的提高。可是css3动画仍是有很多局限性,好比不是全部属性都能参与动画、动画缓动效果太少、没法彻底控制动画过程等等。因此有的时候咱们仍是不得不使用setTimeout或setInterval的方式来实现动画,但是setTimeout和setInterval有着严重的性能问题,虽然某些现代浏览器对这两函个数进行了一些优化,但仍是没法跟css3的动画性能相提并论。这个时候,就该requestAnimationFrame出马了。css
requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个API,目前已在多个浏览器获得了支持,包括IE10+,Firefox,Chrome,Safari,Opera等,在移动设备上,ios6以上版本以及IE mobile 10以上也支持requestAnimationFrame,惟一比较遗憾的是目前安卓上的原生浏览器并不支持requestAnimationFrame,不过对requestAnimationFrame的支持应该是大势所趋了,安卓版本的chrome 16+也是支持requestAnimationFrame的。ios
一、requestAnimationFrame 会把每一帧中的全部DOM操做集中起来,在一次重绘或回流中就完成,而且重绘或回流的时间间隔牢牢跟随浏览器的刷新频率,通常来讲,这个频率为每秒60帧。css3
二、在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这固然就意味着更少的的cpu,gpu和内存使用量。web
像setTimeout、setInterval同样,requestAnimationFrame是一个全局函数。调用requestAnimationFrame后,它会要求浏览器根据本身的频率进行一次重绘,它接收一个回调函数做为参数,在即将开始的浏览器重绘时,会调用这个函数,并会给这个函数传入调用回调函数时的时间做为参数。因为requestAnimationFrame的功效只是一次性的,因此若想达到动画效果,则必须接二连三的调用requestAnimationFrame,就像咱们使用setTimeout来实现动画所作的那样。requestAnimationFrame函数会返回一个资源标识符,能够把它做为参数传入cancelAnimationFrame函数来取消requestAnimationFrame的回调。怎么样,是否是也跟setTimeout的clearTimeout很类似啊。chrome
因此,能够这么说,requestAnimationFrame就是一个性能优化版、专为动画量身打造的setTimeout,不一样的是requestAnimationFrame不是本身指定回调函数运行的时间,而是跟着浏览器内建的刷新频率来执行回调,这固然就能达到浏览器所能实现动画的最佳效果了。浏览器
目前,各个支持requestAnimationFrame的浏览器有些仍是本身的私有实现,因此必须加前缀,对于不支持requestAnimationFrame的浏览器,咱们只能使用setTimeout,由于二者的使用方式几近相同,因此这二者的兼容并不难。对于支持requestAnimationFrame的浏览器,咱们使用requestAnimationFrame,而不支持的咱们优雅降级使用传统的setTimeout。把它们封装一下,就能获得一个统一兼容各大浏览器的API了。性能优化
(function() {
var lastTime = 0;
var vendors = ['webkit', 'moz', 'ms', 'o'];
for( var x=0 ; x<vendors.length ; ++x){
if ( window.requestAnimationFrame && window.cancelAnimationFrame ) {
break;
}
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);
};
}
}());
复制代码
//简化版本bash
window.requestAnimationFrame=window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame ||
function( callback ){
//为了使setTimteout的尽量的接近每秒60帧的效果
window.setTimeout(callback,1000/60);
}
window.cancelAnimationFrame=window.cancelAnimationFrame ||
Window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.msCancelAnimationFrame ||
window.oCancelAnimationFrame ||
function( id ){
//为了使setTimteout的尽量的接近每秒60帧的效果
window.clearTimeout( id );
}
复制代码
<div id="demo" style="position:absolute; width:100px; height:100px; background:#ccc; left:0; top:0;"></div>
<script>
var demo = document.getElementById('demo');
function rander(){
demo.style.left = parseInt(demo.style.left) + 1 + 'px'; //每一帧向右移动1px
}
requestAnimationFrame(function(){
rander();
//当超过300px后才中止
if(parseInt(demo.style.left)<=300){
requestAnimationFrame(arguments.callee);
}
});
</script>
复制代码