移動端模擬滾動

背景

因爲移動端原生滾動的侷限性以及兼容性,部分特定場景的需求沒法知足。例如,筆者最近就接了一個需求:整個頁面分爲三塊,每塊內容的高度不等(但都超過一屏),要求滾動到內容的臨界點有一個停頓的效果,下拉能夠看到下一塊的部份內容,知足條件則滑到下一塊內容。這種場景下,原生的滾動根本沒法支持。所以,本文的主角就亮相了:模擬滾動,即儘量的模擬原生滾動,可是又提供了一些擴展,知足複雜場景的需求。html

本文將從模擬滾動須要實現的功能、技術分析和方案來進行闡述,通讀本文,讀者將對模擬滾動的常見功能和技術要點有必定了解。git

示例:模擬滾動github

知識點

經過移動端的touch系列事件觸發模擬滾動,獲取手指滑動的偏移量,進而改變translateY來進行位置偏移。瀏覽器

滾動容器

滾動容器擁有高度,滾動區域的高度大於滾動容器,在滾動時,咱們對滾動區域進行偏移,以達到滾動的視覺效果。動畫

經過滾動區域的高度能夠經過offsetHeight獲取,可是在如下狀況下會遠遠小於實際高度。code

  • 內聯樣式:在DOM節點生成時,樣式還未渲染完成,此時得到的高度是默認樣式的高度,待樣式渲染完成後,高度可能會有變化
  • 圖片高度:img節點的高度開始是0,在圖片加載完成時,纔會等於圖片高度,所以這裏也會存在偏差

慣性滾動

咱們知道,爲了讓滾動更加流暢,原生的滾動會有一個慣性滾動的效果,即手指快速滑動鬆開後,滾動區域會繼續滾動一段距離後中止。htm

爲了實現這個功能,咱們需求知道手指滑動的速度,根據比率計算目標滾動位置,而後驅動滾動,讓其到達目標位置。事件

這裏筆者嘗試了兩種方案:圖片

  1. 經過requestAnimationFrame不斷進行偏移,直到到達目標位置
  2. 使用transition進行過渡,設置動畫曲線讓其到達目標位置

筆者對比了兩種方案,最終選擇了方案2,緣由是transition過渡會更加的流暢,而requestAnimationFrame會有略微的卡頓,可是transition過渡,咱們實時觸發滾動事件時,很差拿到其當前的位置,查閱了一些資料,筆者最終找到了解決方法,即getComputedStyle,這個API能夠拿到當前頁面渲染的實時樣式,也就是說,哪怕它處於過渡動畫中,咱們能夠實時拿到它的真實位置。get

邊界回彈

當滾動超出邊界時,一般咱們還可讓其繼續滾動,可是這時候會設置阻礙,即滾動速度慢下來,當滾動中止時,咱們再將其拽回到邊界線。咱們能夠經過監聽transitionend事件來判斷慣性滾動中止,這裏的技術點不作過多分析,感興趣能夠在文末中的源碼找答案。

默認行爲

一般狀況下,咱們須要阻止瀏覽器的默認行爲(如滾動),可是這樣也會誤殺一些咱們須要的默認行爲(如超連接跳轉、輸入框聚焦)。

解決方法很簡單,在touchstart觸發時,咱們判斷一下目標節點是否須要阻止默認行爲,好比說tagName=INPUT,咱們不阻止默認行爲。

點擊事件

默認行爲被阻止,綁定在子節點上的點擊事件就沒法觸發了,所以這裏咱們須要判斷一下是否須要觸發點擊事件。能夠經過touch系列事件模擬點擊行爲,而後經過document.createEvent('Event')來主動觸發click事件。

滾動指示器

在滾動區域中,一般在右側會有一個指示器,用於查看當前在整個內容區塊的大概位置。

爲了方便使用,筆者註冊了一系列的鉤子,方便使用者調用,scroll鉤子就是其中之一,在滾動的時候它會實時觸發,在這裏就派上用場了。咱們經過scroll鉤子改變指示器的位置,惟獨要注意的是滾動超出邊界時,指示器會變短而後恢復。

@axe/scroller

基於以上知識點和技術分析,筆者寫了一個模擬滾動js庫(無任何依賴):https://github.com/ansenhuang/axe/blob/master/packages/scroller/README.md

相關文章
相關標籤/搜索