JS實現緩動動畫效果


原理如下:

假設要從數值A變化到數值B,如果是線性運動,則每次移動距離是一樣;如果是緩動,每次移動距離不一樣。那如何才能不一樣呢?很簡單,按比例移動就可以。

例如:每次移動剩余距離的一半。

對吧,超容易理解的。

比方說:你和初戀之間距離是64,每秒移動一半,則,你們之間的距離下一秒就是32, 再下一秒就是16,然后8,然后4,然后2,然后1,然后……你們就在一起了。你們在一起的這個過程就是一個典型的先快后慢的緩動運動過程,如下示意圖:

位置移動標注示意圖

用一個簡單的公式表示就是:

A = A + (B - A) / 2

點擊按鈕執行的是下面的backToTop()方法:

// 滾動到頂部緩動實現
// rate表示緩動速率,默認是2
var backToTop = function (rate) {
    var doc = document.body.scrollTop? document.body : document.documentElement;
    var scrollTop = doc.scrollTop;
    
    var top = function () {
        scrollTop = scrollTop + (0 - scrollTop) / (rate || 2);
        
        // 臨界判斷,終止動畫
        if (scrollTop < 1) {
            doc.scrollTop = 0;
            return;
        }
        doc.scrollTop = scrollTop;
        // 動畫gogogo!
        requestAnimationFrame(top);    
    };
    top();
};

其中,代碼的核心是:

scrollTop = scrollTop + (0 - scrollTop) / (rate || 2);

scrollTop表示公式的A, 滾動到頂部滾動高度是0,因此,上面的0,實際上就是公式的B, 而公式中的2表示緩動速率,實際開發的時候是可以靈活調整的,緩動速率范圍是1到無窮大,速率值越小,運動越快。比如說上面的返回頂部效果,我們把緩動速率改成4,點擊下面的按鈕感受效果:

等比例靠近理論上最終只會無窮靠近,並不會真正的相等,也就是動畫永遠沒有結束的時候,所以說需要做一個臨界判斷,也就是距離小到一定數目的時候,直接等於目標值,並終止動畫。例如,上面的返回頂部,就是當距離頂部滾動高度小於1的時候,直接返回頂部,並終止動畫。

if (scrollTop < 1) {
    doc.scrollTop = 0;
    return;
}


如果項目很多地方使用該算法,每次都寫一遍requestAnimationFrame和邊界判斷是很啰嗦的,於是,我們可以把算法變個身,例如下面這樣:

var _easeout = function(start, end, rate, callback) {
var _end = end;
if (start == end || typeof start != 'number') {
  return;
}
  end = end || 0;
  rate = rate || 2;

var step = function() {
  start = start + (end - start) / rate;
if (Math.abs(start - _end) < 1) {


  console.log('end');
  callback(end, true);
  return;
}
  callback(start, false);
  requestAnimationFrame(step);
};
  step();
};

其中:

  • A是起始位置;
  • B是目標位置;
  • rate是緩動速率;
  • callback是變化的位置回調,支持兩個參數,valueisEnding,表示當前的位置值(數值)以及是否動畫結束了(布爾值);

於是,我們的返回頂部效果可以這么使用:

var doc = document.body.scrollTop !== undefined ? document.body : document.documentElement;
  console.log('start', doc.scrollTop);

$("#back").click(function(){
  console.log('start', doc.scrollTop);
  _easeout(doc.scrollTop, 500, 2, function(value) {
    doc.scrollTop = value;
    });
  })

});


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM