溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么使用JavaScript實現(xiàn)手勢庫

發(fā)布時間:2021-05-07 09:49:48 來源:億速云 閱讀:152 作者:小新 欄目:web開發(fā)

小編給大家分享一下怎么使用JavaScript實現(xiàn)手勢庫,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

JavaScript的特點

1.JavaScript主要用來向HTML頁面添加交互行為。 2.JavaScript可以直接嵌入到HTML頁面,但寫成單獨的js文件有利于結(jié)構(gòu)和行為的分離。 3.JavaScript具有跨平臺特性,在絕大多數(shù)瀏覽器的支持下,可以在多種平臺下運行。

Start 事件

怎么使用JavaScript實現(xiàn)手勢庫

首先我們會觸發(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)

Press 事件

怎么使用JavaScript實現(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,并且放在全局作用域中,讓其他事件可以獲取到這個變量,并且可使用它取消掉這個處理邏輯。

Pan 事件

怎么使用JavaScript實現(xiàn)手勢庫

接下來我們就去監(jiān)聽移動 10px 的 pan 事件,這里就需要我們記錄一開始用戶觸摸屏幕時的 x 和 y 坐標(biāo),當(dāng)用戶移動手指的時候,持續(xù)計算新移動到的位置與初始位置的距離。如果這個距離超過了 10px 就可以觸發(fā)我們的 pan start 的事件了。

所以首先我們需要在 start 函數(shù)中加入 startXstartY 的坐標(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 事件就會被取消。所以這里我們就需要 clearTimeoutpressstarthandler 給清楚掉。

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 事件

怎么使用JavaScript實現(xiàn)手勢庫

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);
  }};

End 事件

到了最后這里我們要處理的就是所有的結(jié)束時間,包括 press-endpan-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è)資訊頻道!

向AI問一下細(xì)節(jié)

免責(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)容。

AI