requestAnimationFrame--用法及轮播动画

requestAnimationFrame ,字面含义是请求动画帧。从API命名来看,和动画有着密切的关系。其用法跟setTimeout差不多,与setTimeout相比,最大的优势是 由浏览器来决定函数的执行时机
形象一点的解释就是:告诉浏览器说 “我这里有一个函数要执行,你有空了帮忙执行一下”,然后浏览器相对比较空闲的时候就给执行了。

用法一:动画

raf api本身的设计就是用来解决js动画的性能问题。那么,为什么raf做动画性能会更好呢?主要原因在于 raf更加智能,它并非加快执行速度,而是适当时候降帧,防止并解决丢帧问题 。当它发现无法维持60fps的频率时,它会把频率降低到30fps来保持帧数的稳定。也就是说如果上一次raf的回调执行时间过长,那么触发下一次raf回调的时间就会缩短,反之亦然,这也是为什么说由浏览器来决定执行时机性能会更好。

(function animloop(){
  window.requestAnimFrame(animloop);
  render();
})();

用法二: 函数节流

在高频率事件中,为了防止16ms内发生多次函数执行,使用raf可保证16ms内只触发一次,这既能保证流畅性也能更好的节省函数执行的开销。 16ms内函数执行多次没有意义,因为显示器16ms刷新一次,多次执行并不会在界面上有任何显示。

举个例子:

var $box = $('#J_num2'),
      $point = $box.find('i');
      $box.on('mousemove',function(e){
          requestAnimationFrame(function(){
          $point.css({
             top : e.pageY,
             left : e.pageX
         })
     })
})

用法三:CPU节能

raf的另一个特性是:如果页面不是激活状态下的话,函数会自动暂停,有效节省了CPU开销。
在移动端,如果页面中有自动播放的轮播图、倒计时或使用 setTimeout/setInterval 来执行任务的定时器。那么 当app进到后台或是锁屏后,webviewcorethread仍然持续占用CPU,导致耗电 。而使用raf可以很简单的解决此类问题。

(function(){
        var timer;
        var $txt = $('#J_num2'),
                num = 0;
        function play(){
            timer = setTimeout(function(){
                  //使用raf实现非激活状态下不运行
                requestAnimationFrame(function(){
                    stop();
                    next();
                });
            },1000)
        }

        function stop(){
            clearTimeout(timer)
        }

        function next(){
            $txt.text(num++);
            play();
        }
        play();
    })();

用法四:分帧初始化

都知道,raf的执行时间约为16.7ms,即为一帧。那么可以使用raf将页面初始化的函数进行打散到每一帧里,这样 可以在初始化时降低CPU及内存开销 。

很多页面,初始化加载时,CPU都会有很明显的波动,就是因为大量的操作都集中到了一点上。

举个例子:
页面中有4个模块,A、B、C、D,在页面加载时进行实例化,一般的写法类似于:

$(function(){
    new A();
    new B();
    new C();
    new D();
})

而使用raf可将每个模块分别初始化,即 每个模块都有16ms的初始化时间

 $(function(){
        var lazyLoadList = [A,B,C,D];
        $.each(lazyloadList, function(index, module){
        window.requestAnimationFrame(function(){new module()});
        }); 

    })

用法五:异步化

raf实际是一种异步化的操作,曾经 setTimeout(function(){},0) 一度成为解决了很多前端疑难杂症的法宝。而现在,可以用raf来代替。

这么多好处,

用setTimeout和setInterval来实现动画-缺点

1、对调用动画的循环机制没有进行优化
2、即使传递毫秒为单位的参数,也不能打到ms的准确性。因为JavaScript是单线程的,可能发生阻塞
3、没有考虑绘制动画的最佳时机

requestAniamationFrame兼容

requestAnimationFrame 不需要使用者指定循环间隔时间,浏览器会基于当前页面是否可见、CPU的负荷情况等来自行决定最佳的帧速率,从而更合理地使用CPU。
如果想做逐帧动画,就应该用这个方法,这就要求动画函数执行会先于浏览器重绘动作。通常,被调用的频率是每秒60次。
回调函数只会传入一个DOMHighResTimeStamp参数,表示函数队列被触发的时间。
requestAnimationFrame返回一个id,用于window.cancelAnimationFrame(id)来取消这个回调函数。
兼容代码:

window.requestAnimationFrame=window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||

            function (callback, element) {
                var start,
                        finish;

                window.setTimeout(function () {
                    start = +new Date();
                    callback(start);
                    finish = +new Date();

                    self.timeout = 1000 / 60 - (finish - start);

                }, self.timeout);
            };
window.cancelNextRequestAnimationFrame = window.cancelRequestAnimationFrame
        || window.webkitCancelAnimationFrame
        || window.webkitCancelRequestAnimationFrame
        || window.mozCancelRequestAnimationFrame
        || window.oCancelRequestAnimationFrame
        || window.msCancelRequestAnimationFrame
        || clearTimeout;

requestAnimationFrame–轮播动画

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <style>
        *{padding:0;margin: 0}
            .outer{width: 100px;height: 100px;overflow:hidden;position: relative;}
            .inner{
                height:100px;list-style-type:none;width: 400px;
            }
            .inner:after{height: 0;content: '';clear: both;visibility: hidden;}
            .inner li{float: left;width: 100px;height: 100px}
            li:nth-child(1){background: red}
            li:nth-child(2){background: black}
            li:nth-child(3){background: yellow}
            li:nth-child(4){background: green}
        </style>
    </head>
    <body>
    <div class="outer">
        <ul class="inner">
            <li></li>
            <li></li>
            <li></li>
            <li></li>
        </ul>
    </div>

    <button>下一步</button>
    <script type="text/javascript">
        var start = null;
        var element = document.querySelector('.inner')
        element.style.position = 'absolute';
        var cur=0,mm=100,timeid
        function step(timestamp) {
          if (!start) start = timestamp;
          var progress = timestamp - start;
          if(cur==3){
            element.style.left=0;
          }else{
            element.style.left = -Math.min(progress / 10+cur*100, (cur+1)*100) + 'px';
          }

          if (progress < 1000) {
            timeid=window.requestAnimationFrame(step);
          }else{
            cur=cur<3?cur+1:0
            window.cancelAnimationFrame(timeid)
            timeid=null
            start=null
            setTimeout(auto,1000)
          }
        }
        var btn=document.querySelector('button')
        btn.onclick=function(){
            auto()
        }
        function auto(){
            if(!timeid){
                console.log(cur)
                timeid=window.requestAnimationFrame(step);
            }
        }
    </script>
    </body>
</html>

参考:http://outofmemory.cn/html/javascript-animation-practice
http://blog.csdn.net/github_37037281/article/details/68957690

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章