HTML5/CSS3時代,咱們要在web裏作動畫選擇其實已經不少了:css
你能夠用CSS3的animattion+keyframes;css3
你也能夠用css3的transition;web
你還能夠用經過在canvas上做圖來實現動畫,也能夠藉助jQuery動畫相關的API方便地實現;canvas
固然最原始的你還可使用window.setTimout()或者window.setInterval()經過不斷更新元素的狀態位置等來實現動畫,前提是畫面的更新頻率要達到每秒60次才能讓肉眼看到流暢的動畫效果。瀏覽器
如今又多了一種實現動畫的方案,那就是還在草案當中的window.requestAnimationFrame()方法。函數
來看MDN上對其給出的詮釋:post
The window.requestAnimationFrame() method tells the browser that you wish to perform an animation and requests that the browser call a specified function to update an animation before the next repaint. The method takes as an argument a callback to be invoked before the repaint. 優化
window.requestAnimationFrame() 將告知瀏覽器你立刻要開始動畫效果了,後者須要在下次動畫前調用相應方法來更新畫面。這個方法就是傳遞給window.requestAnimationFrame()的回調函數。 動畫
也可這個方法原理其實也就跟setTimeout/setInterval差很少,經過遞歸調用同一方法來不斷更新畫面以達到動起來的效果,但它優於setTimeout/setInterval的地方在於它是由瀏覽器專門爲動畫提供的API,在運行時瀏覽器會自動優化方法的調用,而且若是頁面不是激活狀態下的話,動畫會自動暫停,有效節省了CPU開銷。spa
能夠直接調用,也能夠經過window來調用,接收一個函數做爲回調,返回一個ID值,經過把這個ID值傳給window.cancelAnimationFrame()能夠取消該次動畫。
requestAnimationFrame(callback)//callback爲回調函數
模擬一個進度條動畫,初始div寬度爲1px,在step函數中將進度加1而後再更新到div寬度上,在進度達到100以前,一直重複這一過程。
爲了演示方便加了一個運行按鈕(看不到例子請刷新)。
<div id="test" style="width:1px;height:17px;background:#0f0;">0%</div> <input type="button" value="Run" id="run"/>
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
var start = null; var ele = document.getElementById("test"); var progress = 0; function step(timestamp) { progress += 1; ele.style.width = progress + "%"; ele.innerHTML=progress + "%"; if (progress < 100) { requestAnimationFrame(step); } } requestAnimationFrame(step); document.getElementById("run").addEventListener("click", function() { ele.style.width = "1px"; progress = 0; requestAnimationFrame(step); }, false);
既然仍是草案狀態下引入的一個功能,在使用全咱們就須要關心一下各瀏覽器對它的支持狀況了。就目前來講,主流現代瀏覽器都對它提供了支持,請看下圖:
31+ |
26+ |
10+ |
19+ |
6+ |
更爲具體的瀏覽器兼容性能夠在這裏看到。
Polyfill就是墊片,按發明這個詞的人的原話來講,它就是一段這樣的代碼,讓瀏覽器原生地支持咱們指望使用的一些API。
就好比這裏的requestAnimationFrame,在看到了上面的瀏覽器支持狀況後,你就知道了比上面列出的瀏覽器版本老的就不支持該方法,但爲了讓代碼可以有更好的瀏覽器兼容性在老機器上也能運行不報錯,咱們能夠寫一些代碼讓瀏覽器在不支持requestAnimationFrame的狀況下使用window.setTimeout(),這是一種回退(fallback)到過去的方法。
這樣一來,就能夠通俗一點的理解polyfill了,它就是備胎。
下面是由Paul Irish及其餘貢獻者放在GitHub Gist上的代碼片斷,用於在瀏覽器不支持requestAnimationFrame狀況下的回退,回退到使用setTmeout的狀況。固然,若是你肯定代碼是工做在現代瀏覽器中,下面的代碼是沒必要的。
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel // MIT license (function() { var lastTime = 0; var vendors = ['ms', 'moz', 'webkit', 'o']; 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方法時將其指向setTimeout方法。
提到備胎代碼呢,這裏多說一句,在CSS代碼中,咱們也常常使用這種回退的技巧,即對同一條CSS規則,編寫多條以不一樣瀏覽器前綴開頭代碼,或者編寫一條備用樣式。
下面是一個CSS中的備胎代碼的例子:
div { background: rgb(0, 0, 0); /* fallback */ background: rgba(0, 0, 0, 0.5); }
代碼中設置div背景爲黑色帶50%的透明度,但IE9-的瀏覽器是不支持rbga格式的顏色的,因此瀏覽器會回退到上一條CSS規則應用rgb顏色。