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

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