首頁 > web前端 > js教程 > 主體

Javascript動畫的實作原理淺析_javascript技巧

WBOY
發布: 2016-05-16 16:11:45
原創
1121 人瀏覽過

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

複製程式碼 程式碼如下:


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 。

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

複製程式碼 程式碼如下:


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刷新一次),把間隔跟刷新率同步效果更好。

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!