封裝一個簡單的動畫函式

ES6發表於2020-09-28

描述:使傳進來的元素緩慢移動到指定位置(前提此物件必須有定位)

// 簡單動畫函式封裝obj目標物件 target 目標位置
        function animate(obj, target) {
            var timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    // 停止動畫 本質是停止定時器
                    clearInterval(timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';

            }, 30);
        }

        var div = document.querySelector('div');
        var span = document.querySelector('span');
        // 呼叫函式
        animate(div, 300);
        animate(span, 200);

但是這樣我們很多物件新增了多個定時器,影響記憶體,因此我們可以把定時器作為每一個物件的屬性

// 簡單動畫函式封裝obj目標物件 target 目標位置
        // 給不同的元素指定了不同的定時器
        function animate(obj, target) {
            obj.timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    // 停止動畫 本質是停止定時器
                    clearInterval(obj.timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';

            }, 30);
        }

 此處還有一個問題,如果我們通過點選,給一個物件新增多個定時器,會讓元素移動越來越快,因此我們可以每次都清除一下定時器

function animate(obj, target) {
            // 當我們不斷的點選按鈕,這個元素的速度會越來越快,因為開啟了太多的定時器
            // 解決方案就是 讓我們元素只有一個定時器執行
            // 先清除以前的定時器,只保留當前的一個定時器執行
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    // 停止動畫 本質是停止定時器
                    clearInterval(obj.timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';

            }, 30);
        }

        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn = document.querySelector('button');
        // 呼叫函式
        animate(div, 300);
        btn.addEventListener('click', function() {
            animate(span, 200);
        })

在此,我們可以給動畫新增緩動效果(移動速度慢慢減小)

給元素移動的距離為一個變化的步長值,而不是1這個定值,步長值=(目標值-現在位置)/10

var step = (target - obj.offsetLeft) / 10;

obj.style.left = obj.offsetLeft + step + 'px';

但是,當盒子移動完之後,可能與目標距離不準,因為我們涉及到除法了,需要取整,同時,我們如果讓盒子移動到800px,再回來500px,也會不準,因此我們根據步長的值來確定向上還是向下取整

完整程式碼:

// 思路:
        // 1. 讓盒子每次移動的距離慢慢變小, 速度就會慢慢落下來。
        // 2. 核心演算法:(目標值 - 現在的位置) / 10 做為每次移動的距離 步長
        // 3. 停止的條件是: 讓當前盒子位置等於目標位置就停止定時器
        function animate(obj, target) {
            // 先清除以前的定時器,只保留當前的一個定時器執行
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                // 步長值寫到定時器的裡面
                // 把我們步長值改為整數 不要出現小數的問題
                // var step = Math.ceil((target - obj.offsetLeft) / 10);
                var step = (target - obj.offsetLeft) / 10;
                step = step > 0 ? Math.ceil(step) : Math.floor(step);
                if (obj.offsetLeft == target) {
                    // 停止動畫 本質是停止定時器
                    clearInterval(obj.timer);
                }
           // 把每次加1 這個步長值改為一個慢慢變小的值,步長公式:(目標值 - 現在的位置) / 10            
                
                obj.style.left = obj.offsetLeft + step + 'px';

            }, 15);
        }
        var span = document.querySelector('span');
        var btn500 = document.querySelector('.btn500');
        var btn800 = document.querySelector('.btn800');

        btn500.addEventListener('click', function() {
            // 呼叫函式
            animate(span, 500);
        })
        btn800.addEventListener('click', function() {
                // 呼叫函式
                animate(span, 800);
            })
            // 勻速動畫 就是 盒子是當前的位置 +  固定的值 10 
            // 緩動動畫就是  盒子當前的位置 + 變化的值(目標值 - 現在的位置) / 10)

 補充:為動畫函式新增回撥

回撥原理:把一個函式作為一個引數傳遞給另一個函式,當這個函式執行完之後,再執行傳遞過來的函式

btn800.addEventListener('click', function() {
                // 傳遞給animate的第三個引數,是一個函式
                animate(span, 800, function() {
                    // alert('你好嗎');
                    span.style.backgroundColor = 'red';
                });
            })



//當需要停止定時器的時候呼叫這個函式
if (obj.offsetLeft == target) {
                    // 停止動畫 本質是停止定時器
                    clearInterval(obj.timer);
                    // 回撥函式寫到定時器結束裡面
                    if (callback) {
                        // 呼叫函式
                        callback();
                    }
                }

 

相關文章