上一篇介紹了lightning component events的簡單介紹。此篇針對上一篇進行深刻,主要講的內容爲component event中的階段(Phase)。javascript
一. 階段(Phase)的概念html
lightning對於 component event提供了兩種Phase方式,Capture(捕獲階段)以及Bubble(冒泡階段)。這兩種方式和javascript中針對事件處理的Capture以及Bubble很類似。先以javascript中的針對DOM結構事件監聽進行描述。java
以一個demo進行講解。app
<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: 當前觸發事件的元素,即當前在執行事件的元素。spa
針對包含多個元素的執行順序,首先先要知道DOM結構中的事件傳播方式。DOM中針對事件的傳播有三個階段:code
1. capture(捕獲階段):從根元素到事件目標元素(不算目標元素)從上到下,例子中爲 document -> body -> div -> acomponent
2. target(事件目標階段):目標元素,例子中爲 spanhtm
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);
則打印出來的結果爲:
DIV
A
SPAN
若是將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);
則打印出來的結果爲:
A
SPAN
DIV
二.階段(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>
結果展現:
這裏可能有兩個疑問:
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中事件的兩個階段的區別以及用法,兩種用法沒有什麼缺點和優勢的劃分,具體要使用哪一種階段須要考慮你的業務場景要怎樣的順序傳播事件。篇中內容有錯誤的地方歡迎指正,有不懂得地方歡迎留言。