原生 js 實現移動端 Touch 滑動反彈

Levi丶發表於2019-02-16

image

移動端 Touch 滑動反彈

什麼是Touch滑動?就是類似於PC端的滾動事件,但是在移動端是沒有滾動事件的,所以就要用到Touch事件結合js去實現,效果如下:

效果圖

1. 準備工作

什麼是移動端的Touch事件?在移動端Touch事件可以細分成三種,分別是:touchstarttouchmovetouchend,並且touch事件必須要用addEventListener去監聽。

  • touchStart當手指觸碰到螢幕的時候觸發
  • touchmove當手指在螢幕上不斷移動的時候觸發
  • touchend當手指離開螢幕的時候觸發

Touch 事件觸發的 Event 物件:

Touch 事件物件

changedTouchestargetTouchestouches都是偽陣列,裡面裝的是手指列表

三種返回物件的區別:

其實這三種返回的物件,都是表示使用者觸控事件時的手指資訊,之所以是一個偽陣列,是因為有可能出現多指同時觸控,但是在實際工作中一般不去考慮多指的情況。而它們唯一的區別就是在touchstarttouchmove事件的時候,changedTouchestargetTouchestouches都能獲取到手指的資訊,但是在touchend事件的時候,targetTouchestouches物件是不能返回離開螢幕時的手指資訊,只有changedTouches物件能返回。

有哪些手指資訊?

我們可以看下上面的圖片,在changedTouche[0]中,有些值:

2. 基本結構

此案例模擬的是移動端的一種滑動選單效果。

HTML部分:

css部分:

在列表的父盒子上設定一個overflow: hidden屬性,使超出盒子部分的列表暫時隱藏掉,後面會通過js去實現滑動。

效果圖:

基本結構

3. 首次滑動

手指觸控到列表向下滑動的時候,列表應該跟著向下滑動,當手指離開螢幕的時候,列表應該停在滑動的位置。這裡就會用到上面準備階段的知識點了,不明白的可以參考上面的概念。

實現原理:

  • 1、touchstart的時候,獲取手指觸控的落點A,通過這個點物件裡面的clientY屬性,獲取距離頂部可視區的距離;
  • 2、touchmove的時候,獲取手指的點B,同樣的獲取移動時距離頂部可視區的距離;
  • 3、touchmove的時候,還要做另一件事情,就是獲取兩點的差值(B.clientY-A.clientY),將這個差值動態賦值給ulul只需要設定向Y軸方向偏移這個距離,就能實現列表隨手指滑動

先來張示意圖,怎麼通過 js 讓列表滑動起來:

原理圖

示例程式碼:

效果圖:

首次滑動

4. 再次滑動

上面的效果圖,細心的朋友可能已經發現了問題,在第一次的時候,得到了我們想要的效果,但是在第二次的時候,我們繼續向下移動了一段距離,但是ul並沒有接著第一次的位置繼續向下,而是瞬間跳了上去。

問題分析:

雖然第二次是繼續向下移動了一段距離,但是觸控結束後,最終是將此時的差值,重新賦值給了ulY軸偏移,所以視覺上“跳了上去”。

再次滑動

解決方法:

每一次滑動結束之後,都應該記錄下此次滑動的距離,與之前的進行累加,待下一次滑動的時候,ulY軸的偏移值應該是之前的距離加上本次滑動的距離。

  • 新增touchend事件,在該事件裡同樣的可以獲取到本次滑動的距離,將它與上一次的距離相加,賦值給一個全域性變數;
  • touchmove事件裡有點小改動,就是在給ul設定偏移值的時候,除了本次滑動的差值還要加上這個上一次的值;

示意圖:

再次滑動解決方法

示例程式碼:

效果圖:

再次滑動效果圖

5. 限制滑動區間

到上面一步,我們已經可以實現列表的滑動了,但是也存在一個問題,就是向上或者向下的時候沒有限制,上下可以無限的滑動,甚至再用點力,就看不到列表了。為了美觀和實用,這樣肯定不行的,需要給它設定一個區間,設定向上或者向下最多隻能留白多少。

限制滑動區間效果圖

限制向下滑動最大區間:

設定向下最大區間的值比較簡單,直接設定一個值,當上一次滑動的距離加上本次滑動的距離大於這個值的時候,就不讓它再繼續往下滑了,讓他直接等於這個設定的值。

示例程式碼:

限制向上滑動最大區間:

向上滑動時,當ul的底部距盒子底部的距離大於設定值的時候,不讓其繼續向上滑動,關鍵是這個值怎麼去判斷?

限制向上滑動最大區間

求出向上滑動最大值:

求出向上滑動最大值

注意:因為ul是向上滑動的,所以求得的距離前面要加上一個負號(-

示例程式碼:

效果圖:

設定最大滑動區間

認真觀察上圖,雖然成功的設定了最大滑動區間,但是你有沒有發現,一直往一個方向滑動的時候,雖然列表不會繼續往下滑動,但是接著往相反方向滑動的時候,感覺列表滑不動,需要滑一段距離後,列表才會跟著走,這是為什麼呢?因為滑動的過程centerY是一直變的,列表雖然視覺上不動了,但是在touchend事件的時候,它的centerY值一直在累加。解決方法請往下看:

6. 設定反彈區間

“滑動反彈”,這裡的反彈是本篇文章的最後一步,上面說到的問題,就在這裡解決。因為每一次觸發touchend事件的時候,centerY值就累加一次,所以需要在touchend事件裡做判斷。我們設定一個反彈區間,就是當centerY的值大於或者小於某個值的時候,讓它觸發反彈。

設定向上反彈值:

向上的值比較簡單,設定成“0”。為什麼是“0”呢?我們限定只要手指離開時,上一次的滑動距離加上本次的距離> 0的時候,就讓它觸發反彈,並且反彈回0點的位置,也就是兩次滑動的距離和= 0

向上反彈值

示例程式碼:

設定向下反彈值:

向下的值其實跟之前求滑動區間差不多,我們參考下圖,當列表向上滑動,滑動到列表底部的時候,只要此時再向上滑動,就讓它向下反彈。向下反彈值就是-(ul.offsetHeight - draw.offsetHeight),只要滑動的差值小於這個設定值,就讓它向下反彈,並且反彈回設定值的位置。

向下反彈值

示例程式碼:

注意:touchend事件的時候,給列表新增了transition屬性才會有反彈的效果,但是,下一次滑動的時候,touchmove事件的時候,這個屬性還存在,所以就會出現滑動的時候有頓挫感,所以在touchmove事件的時候,一進來就清一下過渡ul.style.transition = 'none';

完成後效果圖:

效果圖

7. 完整程式碼

相關文章