事件機(jī)制是一種非常典型的通訊方式,可以在代碼中的不同對(duì)象之間傳遞信息,也可以在應(yīng)用的不同層面進(jìn)行溝通協(xié)作。今天我們想看來(lái)一下微信小程序框架提供的事件處理機(jī)制。小程序官方文檔對(duì)事件的定義是:- 事件是視圖 ...
事件機(jī)制是一種非常典型的通訊方式,可以在代碼中的不同對(duì)象之間傳遞信息,也可以在應(yīng)用的不同層面進(jìn)行溝通協(xié)作。今天我們想看來(lái)一下微信小程序框架提供的事件處理機(jī)制。
小程序官方文檔對(duì)事件的定義是:
- 事件是視圖層到邏輯層的通信方式
- 事件可以將用戶的行為反饋到邏輯層進(jìn)行處理
- 事件可以綁定在組件上,當(dāng)達(dá)到觸發(fā)事件,就會(huì)執(zhí)行邏輯層中對(duì)應(yīng)的事件處理函數(shù)。
- 事件對(duì)象可以攜帶額外信息,如 id, dataset, touches。
從這里我們可以看到,官方文檔主要將事件用于小程序中針對(duì)用戶交互行為的處理,即視圖層(WXML)到邏輯層(Page)的通信,邏輯層收到這些用戶行為事件后,可以進(jìn)行業(yè)務(wù)處理,然后根據(jù)情況反饋或不反饋結(jié)果給用戶。
好,那我們今天就撇開(kāi)事件的其他用法,專門就講視圖層和邏輯層之間的事件用法。
總體上來(lái)說(shuō),小程序中的事件機(jī)制在工作原理上來(lái)講,和HTML DOM的事件機(jī)制是一致的。在HTML中,我們可以通過(guò)在HTML元素上設(shè)置一個(gè)如onclick="clickHandler(event)"的屬性來(lái)綁定用戶的頁(yè)面點(diǎn)擊事件處理函數(shù)。而在WXML中,我們?yōu)橐粋€(gè)組件綁定一個(gè)事件處理函數(shù),可以使用如下語(yǔ)法來(lái)完成:
這里的bindtap就可以理解為將tap(點(diǎn)擊)事件,綁定到一個(gè)名為tapName的事件處理函數(shù)上來(lái)進(jìn)行處理。然后在相應(yīng)的Page代碼中,我們需要定義這個(gè)tapName函數(shù):
這樣完成了一個(gè)簡(jiǎn)單的tap事件的處理。當(dāng)我們?cè)谛〕绦虻慕缑嫔先c(diǎn)擊這個(gè)顯示為Click me的view組件的時(shí)候,view組件捕獲到這個(gè)tap動(dòng)作,然后告訴Page中的tapName函數(shù),要對(duì)這個(gè)動(dòng)作進(jìn)行處理,同時(shí),它也為tapName函數(shù)提供了足夠多的信息,也就是event對(duì)象,來(lái)幫助我們更好更精準(zhǔn)的處理我們的業(yè)務(wù)邏輯。我們可以來(lái)看一下我們這個(gè)例子中的event對(duì)象里面包含了哪些內(nèi)容:
這里我們可以看到,在event對(duì)象中,包含了事件的名稱,事件目標(biāo)對(duì)象的信息,以及事件發(fā)生的在界面上的位置信息等等。我們?cè)诮M件上設(shè)置的data-hi屬性的值,也在target中的dataset上被攜帶了過(guò)來(lái),這是比較有用的,在實(shí)際開(kāi)發(fā)中,我們可以利用這個(gè)特性,來(lái)傳遞更多視圖層的信息到邏輯層進(jìn)行處理。
如果你有DOM編程的經(jīng)驗(yàn),你就會(huì)在這里想到,小程序里事件的冒泡和非冒泡是怎么處理的?如果你還不了解什么是事件冒泡,那我在這里解釋一下:
在HTML或者WXML這些基于XML的樹(shù)形結(jié)構(gòu)的界面布局方式中,元素與元素之間是有層級(jí)關(guān)系的,子級(jí)元素上觸發(fā)的事件,可以向父級(jí)元素逐層向上傳遞,所以,父級(jí)元素上也可以捕獲子級(jí)元素上的事件并進(jìn)行邏輯處理。
這種事件冒泡的機(jī)制,在實(shí)際的開(kāi)發(fā)中也經(jīng)常會(huì)用到,所以我們有必要來(lái)了解下在小程序中,是如何來(lái)使用冒泡事件的。WXML中分別提供了兩種方式,用來(lái)綁定事件處理函數(shù):
1. 使用 bind 開(kāi)頭的事件綁定,這種綁定不會(huì)阻止冒泡事件向上冒泡
2. 使用 catch 開(kāi)頭的事件綁定,這種綁定可以阻止冒泡事件向上冒泡
直觀起見(jiàn),我們直接來(lái)看一個(gè)示例代碼:
在這個(gè)示例代碼中,有三個(gè)逐級(jí)嵌套的view元素,最里層的是content元素,最外層的為outer-container元素。最里層和最外層的元素上,使用了bind屬性綁定了tap事件的處理函數(shù),而中間的innner-container上,使用了catch屬性進(jìn)行tap事件綁定。
然后,我們嘗試在content上點(diǎn)擊一下,可以看到這樣的結(jié)果:
content和inner-container元素的tap事件處理函數(shù)被執(zhí)行了,而outer-container元素的沒(méi)有被執(zhí)行。這說(shuō)明在點(diǎn)擊content的過(guò)程中,產(chǎn)生的tap事件向父級(jí)元素傳遞,而作為content元素的父級(jí)元素inner-container, 它使用了能阻止事件冒泡的catch方式,所以它在捕獲通過(guò)冒泡形式過(guò)來(lái)的子級(jí)元素事件并執(zhí)行事件處理函數(shù)后,讓該事件停止向上傳遞,因此同樣是父級(jí)元素的outer-contaner,就不再能收到這個(gè)冒泡事件了。
然后,來(lái)看一下,在不同層級(jí)的元素捕獲的event對(duì)象,在數(shù)據(jù)方面有什么特點(diǎn):
我們可以看到,在content的tap事件處理函數(shù)中,event里面的target和currentTarget的id都是content。
而在inner-container中的event對(duì)象里,target的id為content,而currentTarget的id是inner-content。
由此我們可以知道,event對(duì)象中的target是事件產(chǎn)生的源頭組件,而currentTarget則是當(dāng)前捕獲這個(gè)事件的組件。
event對(duì)象中還包含其他一些有用的信息,如touches和changedTouches表示一個(gè)或多個(gè)手指在屏幕上的觸摸位置和變動(dòng)位置等信息,可以用來(lái)實(shí)現(xiàn)多點(diǎn)觸摸的高級(jí)手勢(shì)處理。
最后,關(guān)于事件冒泡,有一點(diǎn)是值得注意一下的:在微信小程序中,并不是所有事件都是冒泡的,從官方文檔了解到,<canvas>組件的觸摸事件不可冒泡。