摘要:你需要知道的隨著前端的發(fā)展,已經(jīng)能夠?qū)崿F(xiàn)非常多的動畫特效,但是仍然存在無法完成的動畫任務(wù)比如頁面滾動,通常的解決方案都是使用中的來設(shè)置定時器來實現(xiàn)動畫特效,比如下面的一個基本的動畫循環(huán)。
你需要知道的requestAnimationFrame
隨著前端的發(fā)展,css已經(jīng)能夠?qū)崿F(xiàn)非常多的動畫特效,但是仍然存在css無法完成的動畫任務(wù)(比如頁面滾動),通常的解決方案都是使用js中的setInterval來設(shè)置定時器來實現(xiàn)動畫特效,比如下面的一個基本的動畫循環(huán)。
(function() { function updateAnimations() { doAnimation1(); doAnimation2(); } setInterval(updateAnimations, 100); })();
該代碼實現(xiàn)的功能是每隔100毫秒執(zhí)行函數(shù)操作來達(dá)到動畫效果,然而,使用計時器真的可靠嗎?
答案當(dāng)然是 no
由于JavaScript是單線程的,所以定時器的實現(xiàn)是在當(dāng)前任務(wù)隊列完成后再執(zhí)行定時器的回調(diào)的,假如當(dāng)前隊列任務(wù)執(zhí)行時間大于定時器設(shè)置的延遲時間,那么定時器就不是那么可靠了,如下所示:
let startTime = new Date().getTime(); setTimeout(()=>{ let endTime = new Date().getTime(); console.log(endTime - startTime); },50) for(let i=0;i<20000;i++) { console.log(1); }
輸出如下
可以看到,設(shè)置了50毫秒后執(zhí)行,實際執(zhí)行延遲時間遠(yuǎn)大于這個數(shù)值,這就會導(dǎo)致動畫效果并不會達(dá)到想要的效果。
動畫是由瀏覽器按照一定的頻率一幀一幀的繪制的,由css實現(xiàn)的動畫的優(yōu)勢就是瀏覽器知道動畫的開始及每一幀的循環(huán)間隔,能夠在恰當(dāng)?shù)臅r間刷新UI,給用戶一種流暢的體驗,而setInterval或setTimeout實現(xiàn)的JavaScript動畫就沒有這么可靠了,因為瀏覽器壓根就無法保證每一幀渲染的時間間隔,一般情況下,每秒平均刷新次數(shù)能夠達(dá)到60幀,就能夠給人流暢的體驗,即每過 1000/60 毫秒渲染新一幀即可,但從上面的例子知,這一點單靠定時器是無法保證的。
為此,requestAnimationFrame應(yīng)運而生,其作用就是讓瀏覽器流暢的執(zhí)行動畫效果??梢詫⑵淅斫鉃閷iT用來實現(xiàn)動畫效果的api,通過這個api,可以告訴瀏覽器某個JavaScript代碼要執(zhí)行動畫,瀏覽器收到通知后,則會運行這些代碼的時候進(jìn)行優(yōu)化,實現(xiàn)流暢的效果,而不再需要開發(fā)人員煩心刷新頻率的問題了。
使用方法如下:
function animationWidth() { var div = document.getElementById("box"); div.style.width = parseInt(div.style.width) + 1 + "px"; if(parseInt(div.style.width) < 200) { requestAnimationFrame(animationWidth) } } requestAnimationFrame(animationWidth);
效果如下(GIF錄制的有點卡。。。實際效果請參考示例):
可以看到,requestAnimationFrame接受一個動畫執(zhí)行函數(shù)作為參數(shù),這個函數(shù)的作用是僅執(zhí)行一幀動畫的渲染,并根據(jù)條件判斷是否結(jié)束,如果動畫沒有結(jié)束,則繼續(xù)調(diào)用requestAnimationFrame并將自身作為參數(shù)傳入。從示例來看,得到了效果平滑流暢的動畫,這樣就巧妙地避開了每一幀動畫渲染的時間間隔問題。
requestAnimationFrame的兼容性參考caniuse
在高級瀏覽器中,開發(fā)人員不用去操心每一幀動畫渲染的時間間隔問題,而針對低版本瀏覽器,則需要使用setTimeout來模擬requestAnimationFrame,且針對不同瀏覽器對requestAnimationFrame的實現(xiàn),這個api的名字也略有差異,針對低版本瀏覽器的模擬requestAnimationFrame的寫法如下(來自張鑫旭大神的博客):
(function() { var lastTime = 0; var vendors = ["webkit", "moz"]; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x] + "RequestAnimationFrame"]; window.cancelAnimationFrame = window[vendors[x] + "CancelAnimationFrame"] || // Webkit中此取消方法的名字變了 window[vendors[x] + "CancelRequestAnimationFrame"]; } if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16.7 - (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); }; } }());
具體含義不做解釋,如果遇到低版本瀏覽器的動畫需求,你只需要把這段代碼丟進(jìn)去定義一個低配版requestAnimationFrame方法即可(珍愛生命,遠(yuǎn)離老瀏覽器?。?。
最后,再貼個部門工作中關(guān)于幀動畫的示例
帥氣的動畫效果
參考:
JavaScript高級程序設(shè)計
CSS3動畫那么強,requestAnimationFrame還有毛線用?
如有錯誤,歡迎指正!
我的github
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107482.html
摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊列被觸發(fā)的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調(diào)函數(shù)只有一個。 requestAnimationFrame 方法讓我們可以在下一幀開始時調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊列被觸發(fā)的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調(diào)函數(shù)只有一個。 requestAnimationFrame 方法讓我們可以在下一幀開始時調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊列被觸發(fā)的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調(diào)函數(shù)只有一個。 requestAnimationFrame 方法讓我們可以在下一幀開始時調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊列被觸發(fā)的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調(diào)函數(shù)只有一個。 requestAnimationFrame 方法讓我們可以在下一幀開始時調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊列被觸發(fā)的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調(diào)函數(shù)只有一個。 requestAnimationFrame 方法讓我們可以在下一幀開始時調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
閱讀 2681·2021-09-13 10:26
閱讀 1932·2021-09-03 10:28
閱讀 2007·2019-08-30 15:44
閱讀 824·2019-08-29 14:07
閱讀 412·2019-08-29 13:12
閱讀 2170·2019-08-26 11:44
閱讀 2361·2019-08-26 11:36
閱讀 2031·2019-08-26 10:19