動畫歷程之滾動的坑

不少時候咱們在web上作動畫通常都是選擇滾動事件來觸發。由於動畫須要判斷是否處於視口內,或者是否到達某個臨界點。而滾動在不一樣的瀏覽器中,不一樣操做系統中的實現都有不一樣。這些就是咱們須要注意的坑~android

滾動的觸發頻率

在咱們先入爲主的思想中,咱們總以爲滾動事件是每PX都會觸發。可是事實並不是如此:
下面請看demo:ios

  1. chrome 移動端滑動模擬,速度是比較慢速的滑動。

觸發頻率
咱們能夠看到觸發的頻率並非按像素的,在時間上,咱們計算可得,間隔大體上是15ms-18ms。而這恰好是每秒60幀的頻率。
而在移動端的瀏覽器或webview中,滾動事件的觸發頻率也是不一樣的。web

  • ios UIwebview (uc qq) 回調事件須要在滾動完成時觸發。
在 iOS UIWebViews中, 在視圖的滾動過程當中,scroll 事件不會被觸發;在滾動結束後,scroll 纔會觸發. Safari 和 WKWebViews不受此bug影響。--MDN events/scroll
  • Android chrome

android chrome
在咱們滾動的時候,能夠看到觸發頻率比PC上的高。chrome

可是滾動觸發事件與滾動距離以及完成的時間有關。有些瀏覽器還有慣性滾動的處理,因此並不能一律而論說觸發必定是每秒60幀的頻率
只是想說明,滾動事件的觸發頻率不是按照PX瀏覽器

滾動的距離

  • element.scrollTop 屬性能夠獲取或設置一個元素的內容垂直滾動的像素數函數

    • document.body.scrollTopchrome不適用
    • document.documentElement.scrollTop chrome適用
    • 推薦獲取滾動值 document.body.scrollTop + document.documentElement.scrollTop 由於二者只有一個生效
  • window.scrollY返回文檔在垂直方向已滾動的像素值。IE9不支持

滾動的模擬

由於滾動事件的兼容性,有一些曲線救國的模擬滾動出現啦,固然,會犧牲必定的性能。
在移動端有touch事件,包含:性能

  • touchstart
  • touchend
  • touchmove
  • touchcancel

方向和距離

經過監聽start,end事件。對開始和結束時pageX,pageY進行計算來判斷滾動的方向,並得到滾動距離。動畫

位置的移動

獲取方向和距離以後,咱們就能夠在touchmove的回調中經過requestAnimationFrame或setTimeout來設置觸發的頻率(時間間隔)。位置的移動經過改變元素的transform:translate來實現,之因此不使用left,是由於使用CSS3的位置變化會讓設備開啓硬件加速,性能比使用left高。spa

再說幾句

減小回調執行時間

由於滾動事件在大部分設備和瀏覽器中觸發的頻率十分高,因此咱們能夠經過節流處理來減小滾動事件中回調函數的執行次數。操作系統

減小回調中DOM操做

由於滾動事件的觸發很快,相對於DOM的操做是很是迅速的,因此在回調事件中若是對於DOM有很複雜的操做,這時候你會發現一些用戶體驗很差的現象,好比閃動,卡頓,位置抖動等....可是沒辦法,有時候要實現這個功能,也只有這一個辦法,哭唧唧~~

滾動動畫

有時咱們須要作一個返回頂部,或者滾動到頁面中的位置的功能。這時候直接改變scrollTop,整個過程會很是的突兀,這時候咱們能夠經過Tween.js來實現滾動的ease,easein這些類型的動畫。
獻上代碼:

// 二次方 緩速動畫 easeout模式
    /*
    * t {number} 開始時間
     * b {number} 開始位置
     * c {number} 結束位置
     * d {number} 結束時間
     */
    function QuadEaseOut(t, b, c, d) {
        return -c * (t /= d) * (t - 2) + b;
    }
    // 判斷是否有requestAnimationFrame
    if (!window.requestAnimationFrame) {
        requestAnimationFrame = function (fn) {
            setTimeout(fn, 17);
        };
    }
    
    /* 
     * target {string} 目標DOM的ID
     */
    function scrollAnimation(target) {
        var startPosition = document.documentElement.scrollTop + document.body.scrollTop;
        var toTarget = document.getElementById(target).offsetTop - startPosition;
        var endTimer = 400;
        var startTimer = 0;
        var step = function () {
            document.documentElement.scrollTop = QuadEaseOut(startTimer, startPosition, toTarget, endTimer);
            document.body.scrollTop = QuadEaseOut(startTimer, startPosition, toTarget, endTimer);
            startTimer += 20;
            if (startTimer <= endTimer) {
                // 繼續運動
                requestAnimationFrame(step);
            } else {
                // 動畫結束
            }
        };
        step();
    }
相關文章
相關標籤/搜索