上一篇介绍了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中事件的两个阶段的区别以及用法,两种用法没有什么缺点和优势的划分,具体要使用哪一种阶段须要考虑你的业务场景要怎样的顺序传播事件。篇中内容有错误的地方欢迎指正,有不懂得地方欢迎留言。