[練習] requestAnimationFrame的使用

以往JS控制的動畫大多使用setInterval 或者setTimeout 每隔一段時間刷新元素的位置,來達到動畫的效果,可是這種方式並不能準確地控制動畫幀率,儘管主流的瀏覽器對於這兩個函數實現的動畫都有必定的優化,可是這依然沒法彌補它們性能問題。主要緣由是由於JavaScript的單線程機制使得其可能在有阻塞的狀況下沒法精確到毫秒觸發。css

requestAnimationFrame()方法正是爲了知足高性能動畫的需求而提供的API,經過setInterval方法控制的動畫其調用的間隔由程序員設置,而requestAnimationFrame()無須設置調用間隔, 它自動緊跟瀏覽器的繪製的幀率(通常瀏覽器的顯示幀率是60fps,差很少每幀間隔16.7ms)html

關於過去的setInterval控制的動畫與requestAnimationFrame()的效果的對比,這裏引用‘艾倫’的帖子中的栗子。原帖地址?動畫requestAnimationFramecss3

setInterval動畫DEMO
requestAnimationFrame動畫DEMO程序員

點擊預覽以上兩個demo能夠明顯感覺到前者有點卡頓,後者更爲流暢。web

另外requestAnimationFrame()在隱藏或不可見的元素中將不會進行重繪或迴流,大大下降了開銷。關於該方法的其餘細節見MDN文檔? window.requestAnimationFrame瀏覽器


以上都是廢話,多寫才能體會。這裏我嘗試用該方法寫了個晃動動畫(點擊黑盒晃動,我的練習並無考慮兼容性):wordpress

動畫練習DEMO函數

JS代碼:性能

//從網頁中獲取一個元素
var box = document.getElementById('box')
shake(box, 500, 15)

//接受三個參數:動畫元素,持續時間,晃動距離
function shake(elm, dur, distance) {
  if (elm) {    
     var dur = dur || 500
     var distance = distance || 10   
//保存原樣式
    var original_css = elm.style.cssText
    elm.addEventListener('click', ani, false)
  } else {
    return 'no param'
  }

  function ani() {
    var start = null
   requestAnimationFrame(act)
//requestAnimationFrame每次調用向callback中傳入一個時間戳,時間戳爲每次調用的時間點
    function act(time_stamp) {
      if(start === null) start = time_stamp
      var elapsed = time_stamp - start
      if ((elapsed / dur) < 1) {
      //乘以4PI,來回往復兩次, 使用正弦函數獲得比例
        elm.style.transform = 'translateX(' + distance * Math.sin((elapsed / dur) * 4 * Math.PI) + 'px' + ')'
        //調用該方法將返回一個ID值用於結束調用
        var time_id = requestAnimationFrame(act)
      } else {
      //恢復原樣式,中止動畫
        elm.style.cssText = original_css
        cancelAnimationFrame(time_id)
      }
    }
  }
}

在實際開發中, 固然儘可能使用css動畫, 畢竟css動畫性能更優。可是對於一些複雜的動畫,好比有暫停,繼續等複雜交互等動畫仍是須要requestAnimationFrame,在張鑫旭大神的這篇文章中CSS3動畫那麼強,requestAnimationFrame還有毛線用? 深刻淺出的闡釋了該方法, 另外他的demo中也有一個很直觀的栗子? 優化

該方法其餘參考資料mark下:
性能更好的js動畫實現方式——requestAnimationFrame
HTML5探祕:用requestAnimationFrame優化Web動畫

相關文章
相關標籤/搜索