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