国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

深入理解requestAnimationFrame的動(dòng)畫(huà)循環(huán)

2019-11-20 08:56:29
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

一、初識(shí)requestAnimationFrame

requestAnimationFrame解決了瀏覽器不知道javascript動(dòng)畫(huà)什么時(shí)候開(kāi)始、不知道最佳循環(huán)間隔時(shí)間的問(wèn)題。它是跟著瀏覽器的繪制走的,如果瀏覽器繪制間隔是16.7ms,它就按這個(gè)間隔繪制;如果瀏覽器繪制間隔是10ms, 它就按10ms繪制。這樣就不會(huì)存在過(guò)度繪制的問(wèn)題,動(dòng)畫(huà)不會(huì)丟幀。

內(nèi)部是這么運(yùn)作的:

瀏覽器頁(yè)面每次要重繪,就會(huì)通知requestAnimationFrame;

這是資源非常高效的一種利用方式。

怎么講呢?

有以下兩點(diǎn):

      1、就算很多個(gè)requestAnimationFrame()要執(zhí)行,瀏覽器只要通知一次就可以了。而setTimeout是多個(gè)獨(dú)立繪制。

      2、一旦頁(yè)面不出于當(dāng)前頁(yè)面(比如:頁(yè)面最小化了),頁(yè)面是不會(huì)進(jìn)行重繪的,自然requestAnimationFrame也不會(huì)觸發(fā)(因?yàn)闆](méi)有通知)。頁(yè)面繪制全部停止,資源高效利用。

二. 動(dòng)畫(huà)的循環(huán)間隔

編寫(xiě)動(dòng)畫(huà)循環(huán)的關(guān)鍵,是要知道延遲時(shí)間多長(zhǎng)合適。一方面,循環(huán)時(shí)間必須足夠短,這樣才能保證動(dòng)畫(huà)效果更平滑流暢;另一方面,循環(huán)還要足夠長(zhǎng),這樣才能保證瀏覽器有能力渲染產(chǎn)生的變化。大多數(shù)顯示器的刷新頻率是60Hz,相當(dāng)于每秒鐘重繪60次。大多數(shù)瀏覽器都會(huì)對(duì)重繪操作加以限制,不超過(guò)顯示器的重繪頻率,因?yàn)榧词钩^(guò)了這個(gè)頻率,用戶(hù)體驗(yàn)也不會(huì)有提升。

因此最平滑動(dòng)畫(huà)的最佳循環(huán)間隔是1000ms/60,約等于17ms。以這個(gè)循環(huán)間隔重繪的動(dòng)畫(huà)是平滑的,因?yàn)檫@個(gè)速度最接近瀏覽器的最高限速。為了適應(yīng)17ms的循環(huán)間隔,多重動(dòng)畫(huà)可能需要加以節(jié)制,以便不會(huì)完成得太快。

雖然與使用多組setTimeout()相比,使用setInterval()的動(dòng)畫(huà)循環(huán)效率更高。但是無(wú)論setTimeout()還是setInterval()都不十分精確。為它們傳入的第二個(gè)參數(shù),實(shí)際上只是指定了把動(dòng)畫(huà)代碼添加到瀏覽器UI線程隊(duì)列以等待執(zhí)行的時(shí)間。如果隊(duì)列前面已經(jīng)加入了其他任務(wù),那動(dòng)畫(huà)代碼就要等前面的任務(wù)執(zhí)行完成后再執(zhí)行。如果UI線程繁忙,比如忙于處理用戶(hù)操作,那么即使把代碼加入隊(duì)列也不會(huì)立即執(zhí)行。

因此,知道什么時(shí)候繪制下一幀是保證動(dòng)畫(huà)平滑的關(guān)鍵。然而,面對(duì)不十分精確的setTimeout()setInterval() ,開(kāi)發(fā)人員至今都沒(méi)有辦法確保瀏覽器按時(shí)繪制下一幀。

以下是幾個(gè)瀏覽器的計(jì)時(shí)器精度:

      IE8及其以下版本瀏覽器: 15.6ms;

      IE9及其以上版本瀏覽器:4ms;

      Firefox和Safari:10ms;

      Chrome:4ms。

更為復(fù)雜的是,瀏覽器開(kāi)始限制后臺(tái)標(biāo)簽頁(yè)或不活動(dòng)標(biāo)簽頁(yè)的計(jì)數(shù)器。因此,即使你優(yōu)化了循環(huán)間隔,可能仍然只能接近你想要的效果。

三. requestAnimationFrame()

Mozilla的 Robert O'Callahan 指出,CSS變換動(dòng)畫(huà)的優(yōu)勢(shì)在于瀏覽器知道動(dòng)畫(huà)什么時(shí)候開(kāi)始,因此會(huì)計(jì)算出正確的循環(huán)間隔,在適當(dāng)?shù)臅r(shí)候刷新UI。而對(duì)于JavaScript動(dòng)畫(huà),瀏覽器就無(wú)從知曉什么時(shí)候開(kāi)始。

因此Robert O'Callahan的方案是,創(chuàng)建一個(gè)新方法mozRequestAnimationFrame() ,通過(guò)它告訴瀏覽器某些代碼將要執(zhí)行動(dòng)畫(huà)。這樣瀏覽器可以在運(yùn)行某些代碼后進(jìn)行適當(dāng)?shù)膬?yōu)化。

setTimeout()setInterval()方法不同,requestAnimationFrame()不需要調(diào)用者指定幀速率,瀏覽器會(huì)自行決定最佳的幀效率。

requestAnimationFrame()方法接收一個(gè)參數(shù),即在重繪屏幕前調(diào)用以個(gè)函數(shù)。這個(gè)函數(shù)負(fù)責(zé)改變下一次重繪時(shí)的DOM樣式。為了創(chuàng)建動(dòng)畫(huà)循環(huán),可以像使用setTimeout()一樣,把多個(gè)對(duì)requestAnimationFrame()的調(diào)用連綴起來(lái)。

如:

function drawFrame() { window.requestAnimationFrame(drawFrame); // animation code...}window.requestAnimationFrame(drawFrame);

三. requestAnimationFrame()的兼容性

3.1 requestAnimationFrame()的兼容性封裝:

由于mozRequestAnimationFrame()是HTML5的新功能,目前各大瀏覽器的支持情況各異。如果希望代碼具備更好的跨平臺(tái)性,可以考慮使用下面的代碼實(shí)現(xiàn)各平臺(tái)兼容性:

if(!window.requestAnimationFrame) { window.requestAnimationFrame = (window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {  var self = this, start, finish;  return window.setTimeout(function() {   start = +new Date();   callback(start);   finish = +new Date();   self.timeout = 1000/60 - (finish - start);  }, self.timeout); });}

這段代碼先檢查了window.requestAnimationFrame函數(shù)的定義是否存在。如果不存在,就遍歷已知的各種瀏覽器實(shí)現(xiàn)并替代該函數(shù)。如果還是找不到一個(gè)與瀏覽器相關(guān)的實(shí)現(xiàn),它最終會(huì)采用基于JavaScript定時(shí)器的動(dòng)畫(huà)以每秒60幀的間隔調(diào)用setTimeout函數(shù)。

mozRequestAnimationFrame()會(huì)接收一個(gè)時(shí)間碼(從1970年1月1日起至今的毫秒數(shù)),表示下一次重繪的實(shí)際發(fā)生時(shí)間。這樣,mozRequestAnimationFrame()就會(huì)根據(jù)這個(gè)時(shí)間碼設(shè)定將來(lái)的某個(gè)時(shí)刻進(jìn)行重繪。

但是webkitRequestAnimationFrame()msRequestAnimationFrame()不會(huì)給回調(diào)函數(shù)傳遞時(shí)間碼,因此無(wú)法知道下一次重繪將發(fā)生在什么時(shí)間。

如果要計(jì)算兩次重繪的時(shí)間間隔,F(xiàn)irefox中可以使用既有的時(shí)間碼,而在Chrome和IE則可以使用不太精確地Date()對(duì)象。

3.2 cancelRequestAnimFrame()的兼容性封裝:

W3C也提供了cancelRequestAnimationFrame()方法,用于取消回調(diào)函數(shù)。requestAnimationFrame()方法會(huì)返回一個(gè)對(duì)象,用做標(biāo)識(shí)回掉函數(shù)身份。若要取消回調(diào)函數(shù)的執(zhí)行,可將其傳給cancelRequestAnimationFrame()

window.cancelRequestAnimFrame = ( function() { return window.cancelAnimationFrame ||  window.webkitCancelRequestAnimationFrame ||  window.mozCancelRequestAnimationFrame ||  window.oCancelRequestAnimationFrame ||  window.msCancelRequestAnimationFrame ||  clearTimeout;} )();

3.3 requestAnimationFrame()升級(jí)版封裝方法:

另外還有一種更優(yōu)雅的requestAnimationFrame()的兼容性封裝方法:

(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);  };}());

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容,希望能對(duì)大家的學(xué)習(xí)或者工作帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 容城县| 黄大仙区| 英吉沙县| 清原| 横峰县| 海原县| 怀柔区| 轮台县| 威远县| 乐陵市| 华宁县| 留坝县| 确山县| 伽师县| 磐石市| 凯里市| 呼图壁县| 古交市| 刚察县| 东至县| 毕节市| 会宁县| 北辰区| 那曲县| 北碚区| 龙泉市| 新巴尔虎右旗| 诸暨市| 湾仔区| 称多县| 武陟县| 涞水县| 双峰县| 齐河县| 万山特区| 罗平县| 丹江口市| 梁河县| 电白县| 东至县| 盐池县|