salesforce lightning零基礎學習(五) 事件階段(component events phase)


上一篇介紹了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);

則打印出來的結果為:

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中事件的兩個階段的區別以及用法,兩種用法沒有什么缺點和優點的划分,具體要使用哪種階段需要考慮你的業務場景要怎樣的順序傳播事件。篇中內容有錯誤的地方歡迎指正,有不懂得地方歡迎留言。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM