微信小程式事件繫結

BWH_Steven發表於2020-09-03

一 通過例項來認識

(一) 給出程式碼

我們直接通過一個例項來引入我們想要講解的內容:

<input type="text" bindinput="handleInput" />
<button bindtap="handletap" data-operation="{{1}}">+</button>
<button bindtap="handletap" data-operation="{{-1}}">-</button>

<view>你輸入的是:{{number}}</view>

上述程式碼就四行,首先是一個 input 輸入框,目的是用來輸入一些值,同時下面標籤就會顯示,接著是兩個 button 用來分別執行 +1 或者 -1 的操作,最後一個 view 標籤就是為了 進行資料輸入或變化的回顯

Page({
  data: {
    number:0
  },
  handleInput(e){
    this.setData({
      number:e.detail.value
    })
  },
  handletap(e){
    const operation = e.currentTarget.dataset.operation
    this.setData({
      number:this.data.number + operation
      // number:this.data.number * 1 + e.currentTarget.dataset.operation
    })
  }
})

這裡給出的就是對應的 js 程式碼,涉及到了對於輸入以及 +1 或者 -1 操作的一個具體邏輯處理,核心就是圍繞 data 中定義的 number 變數進行處理(具體邏輯接著會提到),結合前面的 wxml 程式碼分析一下:

(二) 分析程式碼

分析標籤中屬性中的部分:

bindinput="handleInput"

bindtap="handletap" data-operation="{{-1}}"

  • 繫結事件的關鍵字是 bind 例如上面用到的 bindinputbindtap 就是分別對於輸入和點選事件的一個繫結
  • 而後面的一個名稱例如 handleInput 就是自定義的事件名稱,我們在 js 中書寫方法也是與這個後面的名稱相對應
  • 注:繫結關鍵字為 bind 僅針對此例,並非只是 bind

補充幾個 input 中相對常用的事件繫結屬性

屬性 型別 必填 說明 最低版本
bindinput eventhandle 鍵盤輸入時觸發,event.detail = {value, cursor, keyCode},keyCode 為鍵值,2.1.0 起支援,處理函式可以直接 return 一個字串,將替換輸入框的內容。 1.0.0
bindfocus eventhandle 輸入框聚焦時觸發,event.detail = { value, height },height 為鍵盤高度,在基礎庫 1.9.90 起支援 1.0.0
bindblur eventhandle 輸入框失去焦點時觸發,event.detail = {value: value}

如果想要獲取到輸入框的值,通過時間源物件來獲取 e.detail.value

(1) JS 中賦值問題

輸入框中輸入的值賦值給 data 中的 number,如果按慣性思維直接賦值是有問題的

  • 不能使用 this.data.numer = e.detail.value

  • 不能使用 this.number = e.detail.value

  • 需要使用:

this.setData({
	number:e.detail.value
})

(2) JS 中按鈕傳參問題

新增按鈕點選事件:關鍵字是 bindtap

我們按鈕想要達到的目的是,點選按鈕進行 number 的 +1 或者 -1 ,通過根據我們上面的 js 程式碼可以看出,這裡所採用實現的方式是根據頁面屬性中傳來的引數,進行相加,例如 number + 1 或者 number + (-1) 達到加減效果

但是,直接傳參是有問題的!!!只能通過屬性賦值

正解:bindtap="handletap" data-operation="{{-1}}"

(3) 忘記想要的值對應在哪裡

說明:如果記不住例如:e.detail.value、e.currentTarget.dataset.operation 則可以使用如下的方式,先把事件列印出來

handleInput(e){
    console.log(e);
},

在找到對應的層級

二 事件繫結類別

(一) 分類

我們上面的例子使用了 bind 這個事件繫結關鍵字,但是它會發生冒泡事件

  • 冒泡事件:當一個元件上的事件被觸發後,該事件會向父節點傳遞

  • 非冒泡事件:當一個元件上的事件被觸發後,該事件不會向父節點傳遞

我們還有一些別的選擇,我們下面在 (3) (4) 中會一個一個進行分析

  • bind:普通繫結(會發生冒泡事件)
  • catch:可以阻止事件冒泡
  • capture-bind: 捕獲階段繫結(後面的捕獲流程和冒泡流程還會繼續執行)
  • capture-catch:中斷捕獲階段和取消冒泡階段,在捕獲階段阻止事件的傳遞

(二) 冒泡事件列表

在分析前,我們還要補充一個點,那就是 WXML 的冒泡事件列表:

我們起碼現在知道了 bind 和 catch 的作用,但是正例如我們上面用到的 bindinput 或者 bindtap ,bind 後面的內容又是什麼呢?是固定的還是自定義的呢?這一段我直接貼一段官網的文件說明

型別 觸發條件 最低版本
touchstart 手指觸控動作開始
touchmove 手指觸控後移動
touchcancel 手指觸控動作被打斷,如來電提醒,彈窗
touchend 手指觸控動作結束
tap 手指觸控後馬上離開
longpress 手指觸控後,超過350ms再離開,如果指定了事件回撥函式並觸發了這個事件,tap事件將不被觸發 1.5.0
longtap 手指觸控後,超過350ms再離開(推薦使用longpress事件代替)
transitionend 會在 WXSS transition 或 wx.createAnimation 動畫結束後觸發
animationstart 會在一個 WXSS animation 動畫開始時觸發
animationiteration 會在一個 WXSS animation 一次迭代結束時觸發
animationend 會在一個 WXSS animation 動畫完成時觸發
touchforcechange 在支援 3D Touch 的 iPhone 裝置,重按時會觸發 1.9.90

注:除上表之外的其他元件自定義事件如無特殊宣告都是非冒泡事件,如 form 的submit事件,input 的input事件,scroll-view 的scroll事件,(詳見各個元件)

看完上面的表格,應該就比較清楚了,正因為我們很多事件都是通過手機點一下某個元件等進行,所以 tap 是比較常用的

(三) bind 和 catch

說明:程式碼在下面自取

(1) bind

前面我們提到了,使用 bind 會發生冒泡事件,我們來模擬一下

首先我們寫了三個巢狀的 view 標籤,然後接著使用 bindtap 進行事件繫結,進行一個基本的列印邏輯,看看會有什麼情況發生

當點選中間層後,首先執行了中間層的事件效果,但是最外層的事件效果也被執行了,這也就是冒泡事件發生了

冒泡事件:當一個元件上的事件被觸發後,該事件會向父節點傳遞

非冒泡事件:當一個元件上的事件被觸發後,該事件不會向父節點傳遞

(3) catch

這一次我們仍然點選中間這一層,如果在上面的基礎上,我們將中間層的事件繫結使用 catch,而不是 bind ,結果會是怎樣呢?

結果就是冒泡事件被阻止了,點選後只顯示中間層的事件

(四) capture-bind 和 capture-catch

前面提及到這兩個內容的時候,我們提到了一個概念也就是事件的捕獲階段,簡單說一下:

自基礎庫版本 1.5.0 起,觸控類事件支援捕獲階段。捕獲階段位於冒泡階段之前,且在捕獲階段中,事件到達節點的順序與冒泡階段恰好相反。需要在捕獲階段監聽事件時,可以採用capture-bind、capture-catch關鍵字,後者將中斷捕獲階段和取消冒泡階段。

(1) capture-bind:tap

依舊是剛才的例子,將三層的屬性都修改為 capture-bind:tap="handleTap1" 這種形式的

當我們點選最裡層的內容時,執行結果如下:

即它與包裹它的兩層都執行了,且是從外至內

(2) capture-catch:tap

將三層屬性修改為 capture-catch:tap="handleTap1" 這種形式,點選任意一層:

結果都是隻執行最外層的

(五) 簡單總結

  • bind:點選會觸發它和包裹它的所有事件,且從內向外執行(冒泡事件)
  • catch:點選哪個就觸發哪個,獨立的(阻止冒泡事件)
  • capture-bind: 點選會觸發它和包裹它的所有事件,且從外向內執行
  • capture-catch:如何點選都只會觸發最外層的事件

(六) 程式碼提取

程式碼給出的是 capture-bind:tap 的情況, bindtap 或者 catchtap 以及 capture-catch 只需要將 capture-bind:tap 替換就行了

wxml

<view class="outer" capture-bind:tap="handleTap1">
  這是最外層
  <view class="middle" capture-bind:tap="handleTap2">
    這是中間層
    <view class="inner" capture-bind:tap="handleTap3">
      這是最裡層
    </view>
  </view>
</view>

wxss

.outer {
    text-align: center;
    background-color: red;
    height: 300rpx;
}
.middle {
    background-color: orange;
    width: 60%;
    height: 200rpx;
}
.inner {
    background-color: yellow;
    width: 60%;
    height: 100rpx;
}

結尾

如果文章中有什麼不足,歡迎大家留言交流,感謝朋友們的支援!

如果能幫到你的話,那就來關注我吧!如果您更喜歡微信文章的閱讀方式,可以關注我的公眾號

在這裡的我們素不相識,卻都在為了自己的夢而努力 ❤

一個堅持推送原創開發技術文章的公眾號:理想二旬不止

e

相關文章