上一篇介紹了lightning component events的簡單介紹。此篇針對上一篇進行深入,主要講的内容為component event中的階段(Phase)。
一. 階段(Phase)的概念
lightning對于 component event提供了兩種Phase方式,Capture(捕獲階段)以及Bubble(冒泡階段)。這兩種方式和javascript中針對事件處理的Capture以及Bubble很相似。先以javascript中的針對DOM結構事件監聽進行描述。
以一個demo進行講解。
<html>
<body>
<div id="sampleDivId">
<a id="sampleAId">
<span id="sampleSpanId">
test event phase
</span>
</a>
</div>
</body>
<script>
function clickHandler(e) {
console.log(e.currentTarget.tagName);
}
//第三個參數為 true/false. true代表 capture 方式,false代表bubble方式,預設為false
document.getElementById('sampleSpanId').addEventListener('click',clickHandler);
//document.getElementById('sampleDivId').addEventListener('click',clickHandler);這種方式和下面方式等同,預設為bubble
document.getElementById('sampleDivId').addEventListener('click',clickHandler,false);
document.getElementById(sampleAId).getEventListener('click',clickHandler,false);
</script>
</html>
當我們點選 test event phase 時,因為span,a,div都有事件綁定,是以會執行三個事件,那順序應該如何呢?首先先引入兩個概念:
1. target: 實際觸發者,即設定事件的元素,此處為span元素;
2. currentTarget: 目前觸發事件的元素,即目前在執行事件的元素。
針對包含多個元素的執行順序,首先先要知道DOM結構中的事件傳播方式。DOM中針對事件的傳播有三個階段:
1. capture(捕獲階段):從根元素到事件目标元素(不算目标元素)從上到下,例子中為 document -> body -> div -> a
2. target(事件目标階段):目标元素,例子中為 span
3. bubble(冒泡階段)從目标元素(不算目标元素)到根元素從下到上,例子中為 a -> div -> body -> document
針對每個事件來說, 傳播的順序為 capture -> target -> bubble , 例子中為 document -> body -> div -> a -> span -> a -> div -> body -> document
通過傳播順序我們可以看到,除了事件源,其他元素在傳播的時候都會經曆兩次,但針對其事件僅會調用一次,是以這就是 事件綁定時需要聲明你的事件階段為 capture 還是 bubble,因為不同的階段會有不同的事件的調用順序,即不同的傳播路徑。
demo中針對預設bubble的調用,是以列印出來的結果為:
SPAN
A
DIV
如果把demo中的參數從false轉換為true,
document.getElementById('sampleSpanId').addEventListener('click',clickHandler,true);
document.getElementById('sampleDivId').addEventListener('click',clickHandler,true);
document.getElementById('sampleAId').addEventListener('click',clickHandler,true);
則列印出來的結果為:
如果将demo中的參數部分div标簽設定為false,a标簽設定為true,
document.getElementById('sampleSpanId').addEventListener('click',clickHandler,true);
document.getElementById('sampleDivId').addEventListener('click',clickHandler,false);
document.getElementById('sampleAId').addEventListener('click',clickHandler,true);
二.階段(Phase)在lightning中的使用
官方文檔裡面給出了一個例子很好,在這裡直接引用過來。
1. 建立一個事件:compEvent
1 <aura:event type="COMPONENT" description="Event template">
2 </aura:event>
2.建立eventBubblingEmitter.cmp及其對應的controller.js用于注冊事件以及點選按鈕後觸發事件。
1 <aura:component>
2 <aura:registerEvent name="bubblingEvent" type="c:compEvent" />
3 <lightning:button onclick="{!c.fireEvent}" label="Start Bubbling"/>
4 </aura:component>
1 ({
2 fireEvent : function(cmp) {
3 var cmpEvent = cmp.getEvent("bubblingEvent");
4 cmpEvent.fire();
5 }
6 })
3.建立eventBubblingGrandChild.cmp,包含了eventBubblingEmitter元件以及添加了事件的handler,一個元素可以通過<aura:handler>标簽執行他自身的事件。
1 <aura:component>
2 <aura:handler name="bubblingEvent" event="c:compEvent" action="{!c.handleBubbling}"/>
3 <div class="grandchild">
4 <c:eventBubblingEmitter />
5 </div>
6 </aura:component>
1 ({
2 handleBubbling : function(component, event) {
3 console.log("Grandchild handler for " + event.getName());
4 }
5 })
4.建立eventBubblingChild.cmp。此事件緊使用aura:handler聲明了句柄,并未包含任何其他的component
1 <aura:component>
2 <aura:handler name="bubblingEvent" event="c:compEvent" action="{!c.handleBubbling}"/>
3 <div class="child">
4 {!v.body}
5 </div>
6 </aura:component>
1 ({
2 handleBubbling : function(component, event) {
3 console.log("Child handler for " + event.getName());
4 }
5 })
5.建立eventBubblingParent.cmp以及對應的controller。
1 <aura:component>
2 <aura:handler name="bubblingEvent" event="c:compEvent" action="{!c.handleBubbling}"/>
3 <div class="parent">
4 <c:eventBubblingChild>
5 <c:eventBubblingGrandchild />
6 </c:eventBubblingChild>
7 </div>
8 </aura:component>
1 ({
2 handleBubbling : function(component, event) {
3 console.log("Parent handler for " + event.getName());
4 }
5 })
6. 建立eventBubblingParentApp.app.用于可視化顯示這些元件元素。
1 <aura:application>
2 <c:eventBubblingParent />
3 </aura:application>
結果展示:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5CN4MjNzADOzUTMtQDO1QDM2IDMwIjM3ADOxAjMtYjN5ATM58CX3ADOxAjMvwlN2kDMxkzLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
這裡可能有兩個疑問:
1.為什麼第一個注冊了事件以後,後期的直接使用aura:handler來進行執行事件,而不是每一個都需要注冊事件?
2.為什麼輸出的結果是兩項,而不是三項Log?
分析:
1. 當父元素元件在他的标簽裡面執行個體化了子元素的元素元件後,可以直接使用aura:handler來執行事件。
2.我們可以看到eventBubblingParent.cmp中層級結構為 eventBubblingParent > eventBubblingChild > eventBubblingGrandchild. 盡管eventBubblingChild是eventBubblingGrandchild的父級結構,但是lightning component event中,在元件元素中,隻有最外層元素元件事件才可以被處理。是以這裡面隻會執行上述兩個。
我們來将eventBubblingChild.cmp修改一下:
1 <aura:component>
2 <aura:handler name="bubblingEvent" event="c:compEvent" action="{!c.handleBubbling}"/>
3 <!-- <div class="child">
4 {!v.body}
5 </div> -->
6 <div class="child">
7 <c:eventBubblingGrandchild />
8 </div>
9 </aura:component>
此元件元素中, eventBubblingChild 變成了eventBubblingGrandchild的最外層的元件元素,是以輸出的時候回輸出三個log結果。
我們可以看一下這些元件元素構成的傳播順序:
Parent handler -> Child handler -> grandchild -> Child handler -> Parent handler.
針對Bubble方式,從事件源到根為 grandchild -> Child handler -> Parent handler
針對Capture方式,從根到事件源為Parent handler -> Child handler -> grandchild.
上面的例子都是使用Bubble方式的,下面再次修改eventBubblingChild,使他 handler方式修改成capture。差別僅限于添加phase屬性。
1 <aura:component>
2 <aura:handler name="bubblingEvent" event="c:compEvent" action="{!c.handleBubbling}" phase="capture"/>
3 <!-- <div class="child">
4 {!v.body}
5 </div> -->
6 <div class="child">
7 <c:eventBubblingGrandchild />
8 </div>
9 </aura:component>
事件Event對象也包含了很多方法,常用的有以下幾種:
1.event.setParam(obj):此方法用于事件處理時,添加事件的參數,正常事件聲明時,允許有param,此demo中因為便于展示,是以沒有添加param,參看上節;
2.event.fire():此方法用于觸發事件;
3.event.stopPropagation(): 此方法用于停止事件在其他的元件元素傳播;
上面内容中将Grandchild handler 的controller.js修改成以下:
1 ({
2 handleBubbling : function(component, event) {
3 console.log("Grandchild handler for " + event.getName());
4 event.stopPropagation();
5 }
6 })
結果展示:事件執行完 Grandchild handler以後,因為handler中執行了 stopPropagation方法,則後續的handler均不再執行。
4.event.pause():用于暫停正在執行的事件,直到調用event.resume()方法以後才會繼續傳播事件。這種常用于通過異步傳回結果來判斷後續要如何執行的場景;
5.event.resume():和 event.pause()一組。
總結:此篇主要講解lightning component event中事件的兩個階段的差別以及用法,兩種用法沒有什麼缺點和優點的劃分,具體要使用哪種階段需要考慮你的業務場景要怎樣的順序傳播事件。篇中内容有錯誤的地方歡迎指正,有不懂得地方歡迎留言。
作者:zero
部落格位址:http://www.cnblogs.com/zero-zyq/
本文歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接
個人下載下傳了一些相關學習的PDF檔案,如果需要下載下傳請通路百度雲 點選此處通路 密碼:jhuy
如果文章的内容對你有幫助,歡迎點贊~
為友善手機端檢視部落格,現正在将部落格遷移至微信公衆号:Salesforce零基礎學習,歡迎各位關注。