开新坑啦 × 2

老坑未填新坑又开

关注我的朋友们应该会发现我好久都没发新文章了(其实根本没人关注)。

其实一直都在写新文章只是觉得完成度不够高所以没发出来。

最近一段时间发现在工作中写代码到时候会遇到一些问题,有些是开放性的,需要深入研究来决定是否使用某个技术。有些是稍微了解但没有深入探究的功能。

所以需要编写文章来记录学习的过程。

所以又开新坑啦!新坑就是每周写一些工作上有关代码的问题,字数通常较少(偷懒的借口)。

事件冒泡

今天的话题是代码中事件冒泡机制。

ActionScript (是的我还在用这个过气的语言)和 JavaScript 一样也有类似的事件冒泡机制。

之前有大概了解过冒泡的机制,就是从当前显示对象一层层的像父层级传递事件,像是海底中气泡往上冒的过程,所以称为事件冒泡。

Adobe 的事件流程提到事件流程有三个阶段:捕获阶段,目标阶段,冒泡阶段。

捕获阶段:从舞台 stage 的事件传递到父节点,再传递到子节点触发事件对象的阶段

目标阶段:当前对象为触发事件对象的阶段

冒泡阶段:从触发事件对象阶段,传递到子节点,再传递至到 stage 的阶段。

流程图为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
             +-----------+
+ | stage | ^
| +-----+-----+ |
| | |
| | |
| v |
| +-----+-----+ |
Capture | | Parent | | Bubble
Phase | +-----+-----+ | Phase
| | |
| | |
| v |
| +-----+-----+ |
| | Child | |
v +-----------+ +

Target
Phase

那这样如果在父层级加事件就会触发两次吗?

如果按照默认添加事件的方式只会在冒泡阶段触发一次。

因为添加事件的函数

1
public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void

中的第三个参数 useCapture 默认为 false 。 也就是不在捕获阶段触发,如果设置为 true 也就是会在捕获阶段触发。

而创建事件的时候

1
public function Event(type:String, bubbles:Boolean = false, cancelable:Boolean = false)

事件构造函数中的第二个参数 bubbles 默认为 false,也就是事件不冒泡。

所以通常按默认加事件的方式,父节点是不会触发事件处理函数的。

还好可以在父节点中监听子节点的事件

1
child.addEventListener(EVENT_NAME, handler);

如果需要事件冒泡,需要将 bubbles 设置为 true 。不过通常这个需求都可以通过在父节点的类中监听子节点事件来达成。

除了用事件还可以用回调的方式来实现。不过相比使用回调,事件的有比较明显的有点。事件处理方式灵活(归功于事件流程),一个事件可以有多个监听,而回调就没那么容易做到。