国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Javascript動畫的實現原理淺析

2019-11-20 13:04:10
字體:
來源:轉載
供稿:網友

假設有這樣一個動畫功能需求:把一個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刷新一次),把間隔跟刷新率同步效果更好。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 土默特左旗| 咸丰县| 松溪县| 灵山县| 和政县| 娄烦县| 泸溪县| 呼伦贝尔市| 二连浩特市| 新密市| 桃江县| 苍溪县| 清远市| 武威市| 衡山县| 德化县| 揭阳市| 乌拉特前旗| 板桥市| 江津市| 顺义区| 团风县| 中超| 凤山县| 锡林浩特市| 潮安县| 清远市| 沂源县| 内江市| 永城市| 治县。| 肃宁县| 政和县| 临猗县| 寻甸| 沐川县| 雅江县| 伊宁县| 灵石县| 招远市| 伊金霍洛旗|