因爲移動端原生滾動的侷限性以及兼容性,部分特定場景的需求沒法知足。例如,筆者最近就接了一個需求:整個頁面分爲三塊,每塊內容的高度不等(但都超過一屏),要求滾動到內容的臨界點有一個停頓的效果,下拉能夠看到下一塊的部份內容,知足條件則滑到下一塊內容。這種場景下,原生的滾動根本沒法支持。所以,本文的主角就亮相了:模擬滾動,即儘量的模擬原生滾動,可是又提供了一些擴展,知足複雜場景的需求。html
本文將從模擬滾動須要實現的功能、技術分析和方案來進行闡述,通讀本文,讀者將對模擬滾動的常見功能和技術要點有必定了解。git
示例:模擬滾動github
經過移動端的touch
系列事件觸發模擬滾動,獲取手指滑動的偏移量,進而改變translateY
來進行位置偏移。瀏覽器
滾動容器擁有高度,滾動區域的高度大於滾動容器,在滾動時,咱們對滾動區域進行偏移,以達到滾動的視覺效果。動畫
經過滾動區域的高度能夠經過offsetHeight
獲取,可是在如下狀況下會遠遠小於實際高度。code
咱們知道,爲了讓滾動更加流暢,原生的滾動會有一個慣性滾動的效果,即手指快速滑動鬆開後,滾動區域會繼續滾動一段距離後中止。htm
爲了實現這個功能,咱們需求知道手指滑動的速度,根據比率計算目標滾動位置,而後驅動滾動,讓其到達目標位置。事件
這裏筆者嘗試了兩種方案:圖片
requestAnimationFrame
不斷進行偏移,直到到達目標位置transition
進行過渡,設置動畫曲線讓其到達目標位置筆者對比了兩種方案,最終選擇了方案2,緣由是transition過渡會更加的流暢,而requestAnimationFrame會有略微的卡頓,可是transition過渡,咱們實時觸發滾動事件時,很差拿到其當前的位置,查閱了一些資料,筆者最終找到了解決方法,即getComputedStyle
,這個API能夠拿到當前頁面渲染的實時樣式,也就是說,哪怕它處於過渡動畫中,咱們能夠實時拿到它的真實位置。get
當滾動超出邊界時,一般咱們還可讓其繼續滾動,可是這時候會設置阻礙,即滾動速度慢下來,當滾動中止時,咱們再將其拽回到邊界線。咱們能夠經過監聽transitionend
事件來判斷慣性滾動中止,這裏的技術點不作過多分析,感興趣能夠在文末中的源碼找答案。
一般狀況下,咱們須要阻止瀏覽器的默認行爲(如滾動),可是這樣也會誤殺一些咱們須要的默認行爲(如超連接跳轉、輸入框聚焦)。
解決方法很簡單,在touchstart
觸發時,咱們判斷一下目標節點是否須要阻止默認行爲,好比說tagName=INPUT
,咱們不阻止默認行爲。
默認行爲被阻止,綁定在子節點上的點擊事件就沒法觸發了,所以這裏咱們須要判斷一下是否須要觸發點擊事件。能夠經過touch
系列事件模擬點擊行爲,而後經過document.createEvent('Event')
來主動觸發click事件。
在滾動區域中,一般在右側會有一個指示器,用於查看當前在整個內容區塊的大概位置。
爲了方便使用,筆者註冊了一系列的鉤子,方便使用者調用,scroll
鉤子就是其中之一,在滾動的時候它會實時觸發,在這裏就派上用場了。咱們經過scroll
鉤子改變指示器的位置,惟獨要注意的是滾動超出邊界時,指示器會變短而後恢復。
基於以上知識點和技術分析,筆者寫了一個模擬滾動js庫(無任何依賴):https://github.com/ansenhuang/axe/blob/master/packages/scroller/README.md