從零開始的微信小程序入門教程(四),理解小程序事件與冒泡機制

壹 ❀ 引

我在以前初識WXML與數據綁定兩篇文章中,介紹了小程序靜態模板與樣式相關概念,以及小程序幾種經常使用數據綁定方式,在知道這些知識後,咱們能夠寫一些不算複雜的小程序頁面,並能將一些自定義的數據渲染到視圖層,這很是棒。那麼本文咱們將繼續介紹小程序中比較重要的事件概念,在學習完事件後,咱們可讓小程序具有必定的交互性,那麼本文開始。javascript

貳 ❀ 初識小程序事件

在小程序中,事件是視圖層到邏輯層的通信方式css

好比,咱們能夠將事件綁定在組件上,當用戶操做該組件並觸發事件時,事件會將用戶行爲反饋到邏輯層作處理,也就是對應的執行邏輯層中的事件處理函數。html

固然,有時候行爲反饋不必定是由用戶來主動觸發,舉個生活中的例子,咱們在騰訊視頻看龍嶺迷窟時,當播放到一集結尾,視頻會自動播放下一集。將這個例子拿到小程序中來講,video組件便自帶了bindended事件,只要視頻播放到末尾便會觸發該事件,小程序中存在不少由組件自身提供的事件,因此綜合來講,小程序中的事件由用戶行爲反饋事件組件狀態反饋事件兩部分組成。java

微信小程序除了WXML,WXSS文件以外,還提供了WXS腳本語言,爲何忽然扯到這個呢,由於從基礎庫版本2.4.4開始,支持使用WXS響應事件。針對於IOS環境,WXS腳本執行速度是JavaScript的2-20倍,安卓環境沒啥差異,大致上來理解,用WXS解決事件問題具有必定優點。因爲咱們目前暫未了解WXS腳本,因此這裏先不作探討,後面會專門另起一篇文章介紹WXS腳本以及事件相關說明。學習總不能一口吃成胖子,咱們一步步來。小程序

因此本文仍是主要圍繞用戶行爲反饋事件展開討論,讓你們對於事件先有個基本概念。微信小程序

還記得上篇文章中咱們接觸的第一個點擊事件tap嗎?咱們來重現它,並以此加深對於事件的理解、數組

首先,咱們在index.wxml中與index.js中添加以下代碼:微信

<button bindtap="alert">bindtap</button>
Page({
  data: {},
  alert: function (event) {
    wx.showToast({
      title: '觸發成功', // 標題
      icon: 'success', // 圖標類型,默認success
      duration: 1500 // 提示窗停留時間,默認1500ms
    })
  }
})

有上述例子可知,實現一個事件綁定主要分爲兩步,第一步咱們經過bindtap綁定了一個函數alert,第二咱們在Page構造器中定義對應的事件處理函數alert。當戶點擊button組件時,該組件就會在Page中找到對應的事件函數並執行,這即是一次視圖到邏輯的通信過程。app

須要注意的是,此時咱們使用的事件是tapbind只是一個事件前綴,這就像咱們用原生JS事件時全部事件前都得加一個on,好比onclick,onchange,這是同一個道理。ide

除此以外,小程序中的事件支持bindtap與bind:tap兩種寫法,怎麼用都行。

<button bindtap="alert">bindtap</button>
<button bind:tap="alert">bindtap</button>

好了,在瞭解了事件基本概念後,咱們來一一介紹小程序中提供的用戶交互事件。

因爲大部分事件均與手指觸碰有關,因此爲了你們更好的感覺各個事件的做用,這裏我推薦你們開啓小程序調試器的自動預覽,以下

點擊編譯並預覽後,登錄的微信帳號便可預覽咱們的小程序項目,若是你修改了代碼,記得手動點一次編譯並預覽按鈕。

叄 ❀ 常見事件類型

注意,這裏的事件類型均爲用戶行爲反饋事件,相關說明直接引用官網,有個小規律,小程序中全部事件名均爲小寫單詞拼接,無駝峯拼接狀況,這點你們記住。

事件類型 觸發條件
touchstart 手指觸摸動做開始觸發
touchmove 手指觸摸後移動觸發
touchcancel 手指觸摸動做被打斷,如來電提醒,彈窗
touchend 手指觸摸動做結束
tap 手指觸摸後立刻離開
longpress 手指觸摸後,超過350ms再離開,若是指定了事件回調函數並觸發了這個事件,tap事件將不被觸發(與tap同時定義,優先級更高)
longtap 手指觸摸後,超過350ms再離開(推薦使用longpress事件代替)
transitionend 會在 WXSS transition 或 wx.createAnimation 動畫結束後觸發
animationstart 會在一個 WXSS animation 動畫開始時觸發
animationiteration 會在一個 WXSS animation 一次迭代結束時觸發
animationend 會在一個 WXSS animation 動畫完成時觸發

如今,咱們經過例子一一加深印象,仍是使用上文提供的tap事件例子,JS代碼不變,咱們只須要切換事件名便可:

  1. touchstart事件
<button bindtouchstart="alert">bindtap</button>

模擬器可能還不是很明顯,你們若是經過手機預覽能夠發現,因爲button組件按下去有個背景變灰的漸變,而touchstart事件便是手指觸碰到組件的一瞬間方法就被執行,此時按鈕還沒徹底按下去,你們多體驗幾回。

  1. touchmove事件
<button bindtouchmove="alert">bindtap</button>

這個就很是明顯了,手指按下按鈕徹底變灰後沒執行,必定要咱們按住手指並拖動纔會觸發。

  1. touchcancel事件
<button bindtouchcancel="alert">bindtap</button>

這個我交你們怎麼模擬,在手機上用左手點擊button組件不要放開,用右手點擊小程序更多功能按鈕,此時會彈窗,因爲觸碰被打斷,能夠發現事件被順利觸發。

其次,左手按鈕button,點擊關閉小程序,也就是這個按鈕,此時小程序會暫時退出並保存在手機後臺中,經過後臺直接再進入小程序,咱們會發現touchcancel事件也會觸發。

  1. touchend事件
<button bindtouchend="alert">bindtap</button>

點擊按鈕,長按拖動都不會觸發,直到手指離開屏幕便會觸發。

  1. tap事件
<button bindtap="alert">bindtap</button>

上文中給了例子,雖然官方說手指觸碰後立刻離開觸發,事實證實我按住按鈕十幾秒後離開,也會觸發,我默認理解爲click事件。

  1. longpress事件
<button bindlongpress="alert">bindtap</button>

快速點擊快速鬆開並不會觸發該事件,只有點擊超過350ms時纔會觸發。

  1. 與動畫相關的API,因爲涉及到了小程序動畫,這裏先經過官方動畫例子展現API做用,動畫怎麼玩後面再作介紹(留個坑...)。
<view class="box {{extraClasses}}"
  bindtransitionend="transitionEnd"
  bindanimationstart="animationStart"
  bindanimationiteration="animationIteration"
></view>

<button class="btn" bindtap="triggerTransition">觸發CSS漸變</button>
<button class="btn" bindtap="triggerAnimation">觸發CSS動畫</button>
.box {
  width: 100rpx;
  height: 100rpx;
  margin: 60rpx;
  background: red;
}
.btn {
  margin: 30rpx 60rpx 0;
}

.box-transition {
  transition: all 0.5s;
}
.box-moved {
  margin-left: 590rpx;
}

@keyframes box-ani {
  from {margin-left: 60rpx}
  to {margin-left: 590rpx}
}
.box-animation {
  animation: box-ani 1s alternate infinite;
}
const app = getApp()

Page({
  data: {
    extraClasses: '',
  },
  triggerTransition: function () {
    if (this.data.extraClasses == 'box-transition box-moved') {
      this.setData({
        extraClasses: 'box-transition'
      })
    } else {
      this.setData({
        extraClasses: 'box-transition box-moved'
      })
    }
  },
  triggerAnimation: function () {
    this.setData({
      extraClasses: 'box-animation'
    })
  },
  transitionEnd: function () {
    console.log('漸變已結束')
  },
  animationStart: function () {
    console.log('動畫已開始')
  },
  animationIteration: function () {
    console.log('動畫進行中')
  },
  animationend:function () {
    console.log("動畫結束")
  }
})

肆 ❀ 事件對象

在事件處理函數中,咱們能接受到一個event對象參數,該參數包含了當前事件類型,以及當前組件相關信息,具體屬性以下:

屬性 類型 說明
type String 當前綁定的事件類型
timeStamp Integer 頁面打開到觸發事件所通過的毫秒數
target Object 觸發事件的組件的一些屬性值集合
currentTarget Object 當前組件的一些屬性值集合
detail Object 額外的信息
touches Array 觸摸事件,當前停留在屏幕中的觸摸點信息的數組
changedTouches Array 觸摸事件,當前變化的觸摸點信息的數組

咱們來看個例子:

<button bindtap="alert" id="btn" data-name="聽風是風" data-age="27">bindtap</button>
Page({
  data: {},
  alert: function (event) {
    console.log(event);
  }
})

經過點擊按鈕任意區域,能夠看到控制檯輸出以下數據:

能夠看到組件上自定義的data-**數據,組件X軸Y軸偏移量,鼠標點擊時的座標等等信息均有記錄。

伍 ❀ 複習事件冒泡與理解小程序事件捕獲/冒泡

咱們知道,在JavaScript事件監聽中,分爲捕獲階段--目標階段--冒泡階段三個部分。考慮到有同窗對於該部分知識有遺忘,這裏作個簡單補充。

咱們先來看個JavaScript的例子:

<div class="parent">
    父
    <div class="child">
        子
    </div>
</div>
.parent{
    width: 200px;
    height: 200px;
    background-color: #bbded6;
}
.child{
    width: 100px;
    height: 100px;
    background-color: rgba(255,80,47,1);
}
var parent = document.querySelector(".parent"),
    child = document.querySelector(".child");

parent.addEventListener("click", function () {
    console.log("A");
}, true);
parent.addEventListener("click", function () {
    console.log("B");
});
child.addEventListener("click", function () {
    console.log("D");
}, true);
child.addEventListener("click", function () {
    console.log("C");
}, false);

如今,讓咱們用鼠標點擊紅色區域,猜猜會一次輸出什麼呢?

在說答案以前,咱們先複習下addEventListener事件監聽參數以及含義:

element.addEventListener(event,function,useCapture);

其中event與function爲必填,event表示事件類型,function爲事件處理函數,而useCapture爲選填,它的值爲Boolean值。用於指定事件是否在捕獲或者冒泡階段執行,默認爲false,即在冒泡階段執行,反之在捕獲階段執行。

而上文的例子中,咱們用了一個父盒子包裹了一個子盒子,拋開根元素以及body,捕獲與冒泡以下:

捕獲階段:parent--child

冒泡階段:child--parent

再觀察上述例子關於useCapture的值,因此答案是ADCB

OK,花了點時間用於解釋JS事件監聽的冒泡概念。小程序中事件一樣存在捕獲與冒泡階段。

好比咱們前面所說的bind前綴就表示事件在冒泡階段執行,而若是咱們想事件在捕獲階段執行,能夠在bind前面加上capture,即capture-bind表示捕獲階段執行。

微信小程序中的捕獲與冒泡執行與JS事件監聽保持一致,這裏引用官方一張圖解就一目瞭然了:

<view
  id="parent"
  bind:tap="tap1"
  capture-bind:tap="tap2"
>
  outer view
  <view
    id="child"
    bind:tap="tap3"
    capture-bind:tap="tap4"
  >
    inner view
  </view>
</view>
#parent {
  display: block;
  background-color: #bbded6;
  color: #fff;
}
#child{
  background-color: rgba(255,80,47,1);
}
Page({
  data: {},
  tap1: function (event) {
    console.log('tap1');
  },
  tap2: function (event) {
    console.log('tap2');
  },
  tap3: function (event) {
    console.log('tap3');
  },
  tap4: function (event) {
    console.log('tap4');
  },
})

當咱們點擊inner view區域,能夠看到依次輸出以下:

爲了防止你們疑惑,這裏咱們先作個知識小結,首先咱們前面說了事件支持bind與bind:兩種寫法,這兩種寫法都不會阻止冒泡,因此若是你們分別給父子綁定bind事件,點子區域,會先執行子的bind再執行父的bind,畢竟咱們沒使用capture定義捕獲階段,因此全程就只有冒泡。記住了,bind不會阻止冒泡,添加capture前綴能夠響應捕獲階段。

那麼問題來了,假設咱們想阻止冒泡呢?這時候就得將bind替換爲catch事件了,catch也支持兩種寫法catch與catch:,咱們來試試下面這個例子:

<view
  id="parent"
  catch:tap="tap1"
>
  outer view
  <view
    id="child"
    catch:tap="tap3"
  >
    inner view
  </view>
</view>

如今點擊inner view區域,能夠發現只輸出了tap3,由於冒泡被阻止了。

那有同窗又要問了,若是我在catch前添加capture前綴會怎麼樣?怎麼樣我們修改例子試試不就知道了,看下方例子:

<view
  id="parent"
  bind:tap="tap1"
  capture-catch:tap="tap2"
>
  outer view
  <view
    id="child"
    bind:tap="tap3"
    capture-catch:tap="tap4"
  >
    inner view
  </view>
</view>

咱們將capture-bind都改成capture-catch,能夠發現無論點擊父區域仍是子區域,都只會輸出一個tap2,這是由於capture-catch會中斷捕獲階段和取消冒泡階段。因此無論點擊哪,都是從捕獲階段開始,先捕獲到父,而後中斷捕獲,也不會存在冒泡了,就這麼個意思。

OK,來個小總結。

bind不會阻止冒泡,但若是想抓捕獲階段,能夠添加前綴capture,也就是capture-bind

catch會阻止冒泡,若是添加capture前綴,捕獲階段會中斷的同時,也會阻止冒泡。

最後的最後,官方給了個貼心說明,除了上文中咱們列舉的用戶交互反饋事件以外的其它任意組件狀態反饋事件,除非有特殊聲明,不然都是非冒泡事件。也就是說,上文給的用戶交互反饋事件都是冒泡事件。

好了,關於小程序冒泡機制就聊到這。

陸 ❀ 總結

又花了一天事件整理了小程序事件相關概念,經過本文學習,我想你們對於小程序事件應該有了一個清晰的概念。小程序中的事件分爲用戶交互反饋事件與組件狀態反饋事件(也就是組件自帶的事件)。但整體來講,事件就是視圖層到邏輯層的通信方式。

除此以外,咱們粗略的給出了各個事件的使用區別,幫助你們在特定的需求下能快速定位應該使用哪一個事件。最後,咱們複習了JS事件監聽中捕獲與冒泡的基礎概念,以此爲基礎來了解了小程序中的冒泡機制。知道了原來除了bind還有catch事件,以及咱們還能使用capture前綴來決定是否阻止捕獲與冒泡,這對於往後開發很是有幫助。

好了,關於事件的描述就先說到這了,關於下篇文章我還沒想好寫什麼,我是通讀小程序官方文檔再作的記錄,我也很怕有些知識點讀的遺漏了沒記錄清除,反正我會加油持續更新。

那麼到這裏,本文結束。

對了,我始終以爲我在介紹事件監聽時給的圖片配色在哪裏見過,思考了一番,纔想起來了這是良品鋪子包裝袋的配色,以下圖。

好了,我確實夠無聊...本文結束。

相關文章
相關標籤/搜索