JavaScript 動(dòng)畫掉幀
在使用 JavaScript 進(jìn)行動(dòng)畫效果開發(fā)時(shí),你可能會(huì)遇到一個(gè)重要問題:動(dòng)畫掉幀。盡管我們可以通過限制動(dòng)畫頻率、使用硬件加速和減少頁面元素等技巧來減少掉幀現(xiàn)象,但是要想真正掌握這個(gè)問題,我們需要從原理上了解掉幀是如何出現(xiàn)的。
在講述掉幀原理之前,我們先來通過一個(gè)例子,看看什么是動(dòng)畫掉幀。下面代碼會(huì)在頁面頂部創(chuàng)建一個(gè)圓形,用戶每次點(diǎn)擊時(shí),圓形會(huì)沿著一個(gè)路徑前進(jìn),形成一個(gè)簡(jiǎn)單的動(dòng)畫效果。
const circle = document.createElement('div');
circle.style.width = '50px';
circle.style.height = '50px';
circle.style.borderRadius = '50%';
circle.style.backgroundColor = 'red';
circle.style.position = 'fixed';
circle.style.top = '0px';
circle.style.left = '0px';
document.body.appendChild(circle);
let x = 0;
let y = 0;
function moveCircle() {
x += 10;
y += 10;
circle.style.top = y + 'px';
circle.style.left = x + 'px';
}
document.addEventListener('click', () =>{
setInterval(moveCircle, 16);
});
大家可以在本地運(yùn)行一下代碼,并嘗試以不同速度點(diǎn)擊頁面,來觀察動(dòng)畫效果。可以發(fā)現(xiàn),隨著點(diǎn)擊速度的快速增加,圓形運(yùn)動(dòng)的速度變得越來越快。這是因?yàn)閯?dòng)畫邏輯沒有考慮到掉幀問題,導(dǎo)致定時(shí)器疊加影響了動(dòng)畫效果。
那么,為什么會(huì)出現(xiàn)掉幀現(xiàn)象呢?事實(shí)上,這和動(dòng)畫實(shí)現(xiàn)機(jī)制有關(guān)。在瀏覽器中,動(dòng)畫實(shí)現(xiàn)主要靠 JavaScript 來操作元素屬性,并借助瀏覽器的渲染引擎來完成元素渲染。由于 JavaScript 是單線程運(yùn)行,頁面有多個(gè) JavaScript 動(dòng)畫任務(wù)時(shí),它們會(huì)競(jìng)爭(zhēng)執(zhí)行時(shí)間,可能導(dǎo)致一些任務(wù)的執(zhí)行被延遲或暫停。這就是我們所說的動(dòng)畫掉幀。
那么如何避免動(dòng)畫掉幀呢?首先,我們可以通過調(diào)整動(dòng)畫幀率來控制動(dòng)畫流暢度,以減少掉幀現(xiàn)象的發(fā)生。通常,一個(gè)流暢的動(dòng)畫幀率應(yīng)該在 60 FPS 左右。除此之外,我們還可以使用硬件加速來避免掉幀,例如使用 transform 屬性代替 left 和 top 屬性來移動(dòng)元素,這樣瀏覽器可以利用硬件加速來提高渲染速度,避免掉幀現(xiàn)象。
function moveCircle() {
x += 10;
y += 10;
circle.style.transform = `translate(${x}px, ${y}px)`;
}
最后,我們總結(jié)一下 JavaScript 動(dòng)畫掉幀的原因及解決方案。動(dòng)畫掉幀的原因在于定時(shí)器循環(huán)需要占用 JavaScript 運(yùn)行的主線程,而 JavaScript 的單線程本身就容易出現(xiàn)競(jìng)爭(zhēng)現(xiàn)象,導(dǎo)致動(dòng)畫執(zhí)行時(shí)間不穩(wěn)定。為了減少掉幀現(xiàn)象,可以通過控制動(dòng)畫幀率、使用硬件加速和減少頁面元素等方式來優(yōu)化動(dòng)畫效果。