js中requestAnimationFrame()解讀與使用示例
requestAnimationFrame()
是 JavaScript 中用于實(shí)現(xiàn)動畫效果的一個(gè)重要方法。它告訴瀏覽器你想執(zhí)行動畫,并要求瀏覽器在下次重繪之前調(diào)用指定的回調(diào)函數(shù)來更新動畫。相比傳統(tǒng)的 setTimeout
和 setInterval
,requestAnimationFrame()
更加高效且能夠提供更流暢的動畫。
基本概念
1. 瀏覽器的重繪和回流
瀏覽器通過一個(gè)叫做“幀”的機(jī)制來渲染頁面內(nèi)容。一般來說,瀏覽器每秒會嘗試?yán)L制 60 幀(60FPS),每一幀都需要瀏覽器計(jì)算布局、樣式,并把內(nèi)容繪制到屏幕上。requestAnimationFrame()
是專門為此設(shè)計(jì)的,它會讓你的動畫代碼在瀏覽器的重繪過程中執(zhí)行,確保每次動畫更新都與瀏覽器的刷新頻率同步。
2. 效率和節(jié)能
requestAnimationFrame()
會根據(jù)顯示器的刷新率來自動調(diào)節(jié)幀率,常見的刷新率是 60FPS。如果你的顯示器是 60Hz,requestAnimationFrame()
每秒會回調(diào)約 60 次。如果瀏覽器窗口被最小化,或者切換到另一個(gè)標(biāo)簽頁,requestAnimationFrame()
會暫停執(zhí)行,減少CPU和GPU的負(fù)載。這和 setTimeout
、setInterval
不同,它們會一直執(zhí)行,即使頁面不可見。
使用方法
let start = null; function step(timestamp) { if (!start) start = timestamp; const progress = timestamp - start; // 更新動畫的位置,這里是簡單的例子,假設(shè)移動一個(gè)物體 const element = document.getElementById('box'); element.style.transform = `translateX(${Math.min(progress / 10, 200)}px)`; if (progress < 2000) { // 繼續(xù)動畫,直到經(jīng)過2秒 requestAnimationFrame(step); } } requestAnimationFrame(step);
示例詳解
1. 回調(diào)函數(shù)
requestAnimationFrame()
需要一個(gè)回調(diào)函數(shù)作為參數(shù),這個(gè)回調(diào)函數(shù)會在瀏覽器準(zhǔn)備好繪制下一幀時(shí)被調(diào)用。在上面的示例中,step
函數(shù)就是這個(gè)回調(diào)函數(shù)。
2. timestamp 參數(shù)
瀏覽器會為回調(diào)函數(shù)傳遞一個(gè) timestamp
參數(shù),表示當(dāng)前被請求的動畫幀開始時(shí)的時(shí)間戳。這個(gè) timestamp
是以毫秒為單位的高精度時(shí)間,可以用來計(jì)算動畫進(jìn)行的時(shí)間差。
3. 遞歸調(diào)用
在 step
函數(shù)內(nèi)部,我們通過 requestAnimationFrame()
自己調(diào)用自己,形成一個(gè)動畫的遞歸循環(huán)。每一次調(diào)用 requestAnimationFrame(step)
,瀏覽器都會在下一幀時(shí)再次執(zhí)行 step
函數(shù)。
4. 條件控制
為了停止動畫,我們可以在遞歸調(diào)用時(shí)通過條件判斷,比如在上面的例子中,我們通過 progress < 2000
來控制動畫持續(xù) 2 秒。如果不加這個(gè)條件,動畫會一直進(jìn)行下去。
與 setTimeout 和 setInterval 的比較
function moveBoxWithSetTimeout() { let position = 0; const element = document.getElementById('box'); function update() { position += 5; element.style.transform = `translateX(${position}px)`; if (position < 200) { setTimeout(update, 1000 / 60); // 每秒60次更新 } } update(); } function moveBoxWithRequestAnimationFrame() { let position = 0; const element = document.getElementById('box'); function update() { position += 5; element.style.transform = `translateX(${position}px)`; if (position < 200) { requestAnimationFrame(update); } } requestAnimationFrame(update); }
區(qū)別:
時(shí)間控制:
setTimeout(update, 1000 / 60)
人為指定每秒60幀,但實(shí)際性能可能受限于瀏覽器、CPU 等,不一定精準(zhǔn)。requestAnimationFrame()
由瀏覽器根據(jù)系統(tǒng)的負(fù)載來決定最佳幀率,并與顯示器的刷新同步。
后臺標(biāo)簽頁處理:
setTimeout
和setInterval
在后臺標(biāo)簽頁或最小化時(shí)仍然運(yùn)行,浪費(fèi)資源。requestAnimationFrame()
會在頁面不可見時(shí)暫停,節(jié)省資源。
流暢度:
setTimeout
和setInterval
由于無法和瀏覽器的重繪同步,容易導(dǎo)致卡頓、抖動。requestAnimationFrame()
能提供更加平滑的動畫效果。
多個(gè)動畫場景
你可以通過 requestAnimationFrame()
同時(shí)控制多個(gè)動畫。只需要確保每個(gè)動畫邏輯在回調(diào)函數(shù)中被正確處理。
let box1 = document.getElementById('box1'); let box2 = document.getElementById('box2'); let start = null; function animate(timestamp) { if (!start) start = timestamp; const progress = timestamp - start; box1.style.transform = `translateX(${Math.min(progress / 10, 200)}px)`; box2.style.transform = `translateY(${Math.min(progress / 20, 300)}px)`; if (progress < 2000) { requestAnimationFrame(animate); } } requestAnimationFrame(animate);
上面的代碼演示了:
box1
向右移動,每 10 毫秒移動一個(gè)像素,直到移動 200 像素。box2
向下移動,每 20 毫秒移動一個(gè)像素,直到移動 300 像素。
多個(gè)元素的動畫可以在同一個(gè) requestAnimationFrame
回調(diào)中進(jìn)行,這樣它們會同步進(jìn)行,保證幀率的一致性。
動畫的取消
requestAnimationFrame()
返回一個(gè)唯一的整數(shù) ID,代表該動畫幀請求??梢允褂?nbsp;cancelAnimationFrame()
取消這個(gè)動畫。
let animationId; function step(timestamp) { // 動畫邏輯 if (progress < 2000) { animationId = requestAnimationFrame(step); } } // 開始動畫 animationId = requestAnimationFrame(step); // 取消動畫 cancelAnimationFrame(animationId);
總結(jié)
- 同步與瀏覽器刷新頻率:
requestAnimationFrame()
是與顯示器的刷新率同步的動畫方法,通常會以 60FPS 執(zhí)行。 - 高效與節(jié)能:在頁面不可見時(shí),
requestAnimationFrame()
會暫停執(zhí)行,避免不必要的計(jì)算。 - 流暢的動畫體驗(yàn):由于它與瀏覽器的重繪同步,能帶來更加流暢的動畫效果。
通過掌握 requestAnimationFrame()
,你可以更輕松地創(chuàng)建流暢且高效的動畫效果,它是現(xiàn)代 Web 動畫開發(fā)的核心工具之一。
到此這篇關(guān)于js中requestAnimationFrame()解讀與使用示例的文章就介紹到這了,更多相關(guān)js requestAnimationFrame()內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js中刪除數(shù)組中的某一元素實(shí)例(無下標(biāo)時(shí))
下面小編就為大家?guī)硪黄猨s中刪除數(shù)組中的某一元素實(shí)例(無下標(biāo)時(shí))。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02原生js實(shí)現(xiàn)密碼強(qiáng)度驗(yàn)證功能
這篇文章主要為大家詳細(xì)介紹了原生js實(shí)現(xiàn)密碼強(qiáng)度驗(yàn)證功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03簡單時(shí)間提示DEMO從0開始一直進(jìn)行計(jì)時(shí)
點(diǎn)擊按鈕輸入框會從0開始一直進(jìn)行計(jì)時(shí),具體的實(shí)現(xiàn)示例如下,感興趣的朋友可以嘗試操作下哦2013-11-11ES6中l(wèi)et、const的區(qū)別及變量的解構(gòu)賦值操作方法實(shí)例分析
這篇文章主要介紹了ES6中l(wèi)et、const的區(qū)別及變量的解構(gòu)賦值操作方法,結(jié)合實(shí)例形式分析了ES6中l(wèi)et、const的功能、原理、使用方法及數(shù)組、字符串、函數(shù)參數(shù)等解構(gòu)賦值相關(guān)操作技巧,需要的朋友可以參考下2019-10-10用js模仿word格式刷功能實(shí)現(xiàn)代碼 [推薦]
非常不錯(cuò)的模仿word格式刷實(shí)現(xiàn)代碼。推薦大家參考下思路。2009-07-07微信小程序?qū)崿F(xiàn)選項(xiàng)卡滑動切換
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)選項(xiàng)卡滑動切換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10