H5頁面滾動阻尼效果實現

BeckyWang發表於2019-03-04

功能描述

  • 要求

    • 頁面分為AB兩個區域

    • 當手機可視區的底部接觸到 “阻尼帶” 的時候,有個上拉彈性過程

      • 當上拉到一定閾值程度就直接把B區頂部彈到手機可視區的頂部,讓可視區從B區開始顯示
      • 當上拉程度未到閾值,就回彈復原
    • 當手機可視區從B區向上滾動時候,B區頂部接觸帶“阻尼帶”,有個下拉彈性過程

      • 當下拉到一定閾值程度就直接把A區底部彈到手機可視區的底部,讓可視區從A區底部向上開始顯示
      • 當下拉程度未到閾值,就回彈復原
  • 提示

    • 可用jQuery實現

具體實現過程

首先什麼是阻尼效果?上網查閱:

阻尼(英語:damping)是指任何振動系統在振動中,由於外界作用和/或系統本身固有的原因引起的振動幅度逐漸下降的特性,以及此一特性的量化表徵。

好吧,生澀難懂,沒能理解。不過網上有說此效果在iPhone上比較常見,直接上圖比較容易理解:

阻尼效果

簡單來說,就是介面滑動到了最底部或最頂部仍可以比實際的內容多滑動一段距離然後回彈的彈性效果。 從效果中可以看出,有三個重點:

  • 滑動到最頂部或最底部才出現。
  • 表現出比實際的內容多滑動一段距離,實際操作知道,多滑動的距離即是手指在螢幕上滑動的距離。
  • 放開手之後,有回彈效果。

已經知道什麼是阻尼效果了,現在思考如何去實現。 對於第二點,我們可以監聽 touchstart, touchmove, touchend 事件,跟滑鼠拖拽的原理類似:

  1. touchstart 時,記下起點位置;
  2. touchmove 實時計算滑動的距離。
  3. touchend 時,能得到最終的滑動距離,跟設定的閾值比較。進入到頁面自動控制階段:大於閾值則讓頁面滑動到下一頁,小於閾值則恢復到起始位置。

在我實現的過程中,想過兩種方案。

  1. 利用Js 大致思路是,通過監測滾輪事件,檢測到頁面已經滑動到最底部(最頂部同理),計算手指在頁面的滑動距離,touchmove事件觸發時,給下面的阻尼帶增加padding-bottom,造成頁面跟著手指多滑動一段距離的假象。 缺點:利用js實現動畫比較耗費效能。

  2. 利用css 第二個方案採用css動畫,頁面多滑動一段距離,實際上也可以通過把頁面往手指滑動的方向translate一段距離,這個時候頁面只要背景色相同,也可以實現相同效果。 因為translate可以出發瀏覽器硬體加速,可以保證效能。

能用 css 做的,絕對不要用 js 解決。

但是在第二種方案實現過程中發現一個問題,如果我們在滑動一段距離後才到達最底部,這時候不鬆開手,又往回滑,就會出現bug。

bug

我是通過監測滾動條的位置判斷是否到達底部。

$(document).scroll(() => {
    isBottom = document.scrollTop() >= $(document).height() - $(window).height();
});
複製程式碼

因為往回滑的過程,滾動條也往上滑動,導致isBottom錯誤,出現bug。

上網查閱了很多資料,沒有找到理想的解決辦法,但是找到一個移動端外掛:Swiper,這是純javascript打造的滑動特效外掛,面向手機、平板電腦等移動終端。這個外掛也實現了阻尼效果。 通過看它的原始碼發現,Swiper也是利用translate的方法,將頁面往上移動一段距離,但是滾動條是自己實現的,也就是通過設定外面容器的overflow: hidden來禁用原生滾動條,自己重新實現一個。 道理很簡單,我們可以通過touch事件translate頁面,同樣也可以translate滾動條,這樣達到自己可控。

找到解決辦法,仿照Swiper的思路(但是省去了滾動條部分的程式碼實現,就是頁面沒有滾動條),粗略實現了阻尼效果。

最終效果

詳細程式碼見我的github。其中利用了webpack進行打包編譯。

相關文章