萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> Javascript動畫的實現原理淺析

Javascript動畫的實現原理淺析

 這篇文章主要介紹了Javascript動畫的實現原理淺析,本文用兩個實例來解釋Javascript動畫的實現原理,需要的朋友可以參考下

   

假設有這樣一個動畫功能需求:把一個div的寬度從100px變化到200px。寫出來的代碼可能是這樣的:

代碼如下:
<div id="test1" style="width: 100px; height: 100px; background: blue; color: white;"></div>
function animate1(element, endValue, duration) {
var startTime = new Date(),
startValue = parseInt(element.style.width),
step = 1;

var timerId = setInterval(function() {
var nextValue = parseInt(element.style.width) + step;
element.style.width = nextValue + 'px';
if (nextValue >= endValue) {
clearInterval(timerId);
// 顯示動畫耗時
element.innerHTML = new Date - startTime;
}
}, duration / (endValue - startValue) * step);
}

 

animate1(document.getElementById('test1'), 200, 1000);


原理是每隔一定時間增加1px,一直到200px為止。然而,動畫結束後顯示的耗時卻不止1s(一般是1.5s左右)。究其原因,是因為setInterval並不能嚴格保證執行間隔。

 

有沒有更好的做法呢?下面先來看一道小學數學題:

代碼如下:
A樓和B樓相距100米,一個人勻速從A樓走到B樓,走了5分鐘到達目的地,問第3分鐘時他距離A樓多遠?
勻速運動中計算某個時刻路程的計算公式為:路程 * 當前時間 / 時間 。所以答案應為 100 * 3 / 5 = 60 。

 

這道題帶來的啟發是,某個時刻的路程是可以通過特定公式計算出來的。同理,動畫過程中某個時刻的值也可以通過公式計算出來,而不是累加得出:

 

代碼如下:
<div id="test2" style="width: 100px; height: 100px; background: red; color: white;"></div>
function animate2(element, endValue, duration) {
var startTime = new Date(),
startValue = parseInt(element.style.width);

 

var timerId = setInterval(function() {
var percentage = (new Date - startTime) / duration;

var stepValue = startValue + (endValue - startValue) * percentage;
element.style.width = stepValue + 'px';

if (percentage >= 1) {
clearInterval(timerId);
element.innerHTML = new Date - startTime;
}
}, 13);
}

animate2(document.getElementById('test2'), 200, 1000);

 

這樣改良之後,可以看到動畫執行耗時最多只會有10幾ms的誤差。但是問題還沒完全解決,在浏覽器開發工具中檢查test2元素可以發現,test2的最終寬度可能不止200px。仔細檢查animate2函數的代碼可以發現:

1.percentage的值可能大於1,可以通過Math.min限制最大值解決。
2.即使保證了percentage的值不大於1,只要endValue或startValue為小數,(endValue - startValue) * percentage的值也可能產生誤差,因為Javascript小數運算的精度不夠。其實我們要保證的只是最終值的准確性,所以在percentage為1的時候,直接使用endValue即可。

於是,animate2函數的代碼修改為:

代碼如下:
function animate2(element, endValue, duration) {
var startTime = new Date(),
startValue = parseInt(element.style.width);

 

var timerId = setInterval(function() {
// 保證百分率不大於1
var percentage = Math.min(1, (new Date - startTime) / duration);

var stepValue;
if (percentage >= 1) {
// 保證最終值的准確性
stepValue = endValue;
} else {
stepValue = startValue + (endValue - startValue) * percentage;
}
element.style.width = stepValue + 'px';

if (percentage >= 1) {
clearInterval(timerId);
element.innerHTML = new Date - startTime;
}
}, 13);
}

 

還有最後一個疑問:setInterval的間隔為何設為13ms?原因是當下顯示器的刷新率一般不超過75Hz(即每秒刷新75次,也就是每隔約13ms刷新一次),把間隔跟刷新率同步效果更好。

copyright © 萬盛學電腦網 all rights reserved