您好,登錄后才能下訂單哦!
小編給大家分享一下怎么使用JavaScript實現手勢庫,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
1.JavaScript主要用來向HTML頁面添加交互行為。 2.JavaScript可以直接嵌入到HTML頁面,但寫成單獨的js文件有利于結構和行為的分離。 3.JavaScript具有跨平臺特性,在絕大多數瀏覽器的支持下,可以在多種平臺下運行。
首先我們會觸發一個 start 事件,也就是當我們手指觸摸到屏幕時第一個觸發的事件。這時會有三種情況:
手指松開
會觸發 end 事件,這樣就構成一個 tap
點擊的行為
通過監聽 end 事件來實現即可
手指拖動超過 10 px
這種就是 pan start
拖動的行為
我們可以在 move 事件判斷當前與上一個觸點的距離
手指停留在當前位置超過 0.5s
這種就是 press start
按壓的行為
我們可以添加一個 setTimeout 來實現
所以我們第一步就是在 start
函數中加入一個 setTimout
的 handler 處理程序。
let handler;let start = point => { handler = setTimeout(() => { console.log('presss '); }, 500);};
一般來說 press
是我們比較常見的一個行為。但是實際上這里是 press start 事件,后面還會跟隨著一個 press end 的事件。我們也可以統稱這個為 press
事件,然后這個手勢庫的使用者只需要監聽這個 press
事件即可,極少的情況下是需要監聽 press end
事件的。
這里我們需要注意的是,當我們觸發其他的事件的時候,這個 500 毫秒的 setTimout 是有可能會被取消掉的。所以我們需要給這段邏輯一個 handler
,并且放在全局作用域中,讓其他事件可以獲取到這個變量,并且可使用它取消掉這個處理邏輯。
接下來我們就去監聽移動 10px 的 pan
事件,這里就需要我們記錄一開始用戶觸摸屏幕時的 x 和 y 坐標,當用戶移動手指的時候,持續計算新移動到的位置與初始位置的距離。如果這個距離超過了 10px 就可以觸發我們的 pan start
的事件了。
所以首先我們需要在 start 函數中加入 startX
和 startY
的坐標記錄,這里要注意的是,因為這兩個值都是會在多個地方被使用的,所以也是需要在全局作用域中聲明。
然后在 move 函數中計算當前觸點與起點的直徑距離。這里我們需要用到數學中的直徑運算公式 z 2 x^2 + y^2 = z^2x 2 +y 2 =z 2 ,而這里面的 x 是 當前觸點的 x 坐標 - 起點的 x 坐標 的 x 軸的距離, y 就是 當前出點的 y 坐標 - 起點的 y 坐標 運算出來的 y 軸的距離。最終兩個距離二次冪相加就是直徑距離的二次冪。
在代碼中我們一般都會盡量避免使用根號運算,因為根號運算會對性能有一定的影響。我們知道最終要判斷的是直徑距離是否是大于一個固定的 10px。那就是說 z = 10,而 z 的二次冪就是 100,所以我們直接判斷這個直徑距離是否大于 100 即可。
這里還有一個需要注意的,就是當我們手指移動超過 10px 之后,如果我們手指沒有離開屏幕而是往回移動了,這樣的話我們距離起點已經不夠 10px了。但是這個其實也是算 pan 事件,因為我們確實有移動超過 10px 距離,超過這個距離之后所有的移動都是屬于 pan 事件。
所以我們需要一個 isPan
的狀態,第一次移動超出 10px 的時候,就會觸發 pan-start
事件,并且把 isPan
置為 true,而后面的所有移動都會觸發 pan
事件。
根據我們上面講到的 press
事件,如果我們按下手指后 0.5 秒內出現了移動,那么 press
事件就會被取消。所以這里我們就需要 clearTimeout
把 pressstart
的 handler
給清楚掉。
let handler;let startX, startY;let isPan = false;let start = point => { (startX = point.clientX), (startY = point.clientY); isPan = false; handler = setTimeout(() => { console.log('pressstart'); }, 500);};let move = point => { let dx = point.clientX - startX, dy = point.clientY - startY; let d = dx ** 2 + dy ** 2; if (!isPan && d > 100) { isPan = true; console.log('pan-start'); clearTimeout(handler); } if (isPan) { console.log(dx, dy); console.log('pan'); }};
Tap 的這個邏輯我們可以在 end 事件里面去檢查。首先我們默認有一個 isTap
等于 true 的狀態,如果我們觸發了 pan 事件的話,那就不會去觸發 tap 的邏輯了,所以 tap 和 pan 是互斥的關系。但是為了不讓它們變得很耦合,所以我們不使用原有的 isPan 作為判斷狀態,而是另外聲明一個 isTap
的狀態來記錄。
這里我們 tap 和 pan 都有單獨的狀態,那么我們 press 也不例外,所以也給 press 加上一個 isPress
的狀態,它的默認值是 false。如果我們 0.5 秒的定時器被觸發了,isPress
也就會變成 true。
既然我們給每個事件都加入了狀態,那么這里我們就給每一個事件觸發的時候設置好這些狀態的值。
press 時
isTap = false
isPan = false
isPress = true
pan 時
isTap = false
isPan = true
isPress = false
tap 時
isTap = true
isPan = false
isPress = false
如果我們發現用戶沒有移動,也沒有按住觸屏超過 0.5 秒,當用戶離開屏幕時就會調用 end 函數,這個時候我們就可以認定用戶的操作就是 tap。這里我們要注意的是,我們 press 的 0.5 秒定時器是沒有被關閉的,所以我們在 isTap 的邏輯中需要 clearTimeout(handler)
。
說到取消 press 定時器,其實我們 handler 的回調函數中,也需要做一個保護代碼邏輯,在觸發了 press-start 之后,我們需要保證每次點擊屏幕只會觸發一次,所以在 setTimout 的回調函數中的最后,我們需要加上 handler = null
。這樣只要 press-start 觸發了,就不會再被觸發。
let handler;let startX, startY;let isPan = false, isPress = false, isTap = false;let start = point => { (startX = point.clientX), (startY = point.clientY); isPan = false; isTap = true; isPress = false; handler = setTimeout(() => { isPan = false; isTap = false; isPress = true; console.log('press-start'); handler = null; }, 500);};let move = point => { let dx = point.clientX - startX, dy = point.clientY - startY; let d = dx ** 2 + dy ** 2; if (!isPan && d > 100) { isPan = true; isTap = false; isPress = false; console.log('pan-start'); clearTimeout(handler); } if (isPan) { console.log(dx, dy); console.log('pan'); }};let end = point => { if (isTap) { console.log('tap'); clearTimeout(handler); }};
到了最后這里我們要處理的就是所有的結束時間,包括 press-end
和 pan-end
。
這兩個 end 事件都會在 end 函數中判斷所得,如果在用戶操作的過程中觸發了 pan-start
或者 press-start
事件,到了 end 函數這里,對應的狀態就會是 true。
所以我們對 end 函數做了以下改造:
let end = point => { if (isTap) { console.log('tap'); clearTimeout(handler); } if (isPan) { console.log('pan-end'); } if (isPress) { console.log('press-end'); }};
最后我們需要在 cancel 事件觸發的時候,清楚掉 press 事件的 setTimeout。既然我們的操作被打斷了,那也不可能會觸發我們的長按事件了。
// 加入 cancellet cancel = point => { clearTimeout(handler); console.log('cancel');};
我們除了 flick
的邏輯,我們已經完成所有手勢庫里面的事件了。并且也能正確的區分這幾種手勢操作了。
以上是“怎么使用JavaScript實現手勢庫”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。