21.5. 判断当前事件阶段
我们在"为捕获阶段和冒泡阶段都注册父级侦听器"中,通过2次调用addEventListener(), 我们可以为捕获和冒泡阶段独立注册一个单独的事件侦听器函数.同样地,在" useCapture 属性的双重用途"我们学到当以useCapture 为false 注册一个侦听器,这个侦听器会在目标阶段或者冒泡阶段被执行。所以,当一个事件侦听器函数被一个事件调用而这个事件当前的阶段为未知,AS提供了
Event 类一个实例属性eventPhase, 这个属性可以在事件侦听器函数里面使用来判断事件的当前阶段。
eventPhase 属性表明了当前的事件发送是处于捕获、目标、还是冒泡阶段。当一个事件发送于捕获阶段, eventPhase 被设为 EventPhase.CAPTURING_PHASE, 表明目标对象还没有接受到事件通知。如果一个事件发送于目标阶段, eventPhase 被设置为 EventPhase.AT_TARGET, 表明目标当前正在处理事件。当一个事件被发送于冒泡阶段,eventPhase 被设置为EventPhase.BUBBLING_PHASE, 表明目标对象已经结束了对事件的处理。
代表性地, EventPhase.CAPTURING_PHASE, EventPhase.AT_TARGET,以及
EventPhase.BUBBLING_PHASE分别是值为1, 2, and 3的常量。但是这些值会根据工程而变化,所以不要直接使用值。而是在侦听器函数中将事件的eventPhase 属性于EventPhase 类的常量进行比较 like this:
private function someListener(e:Event):void {
if (e.eventPhase == EventPhase.AT_TARGET) { // 不要用 if (e.eventPhase == 2)
// 这个侦听器是在目标阶段被调用...
}
}
下面的代码是eventPhase 属性的一般用法。首先,代码添加了一个TextField 对象到Stage 。然后代码为舞台的捕获阶段注册了clickListener() 侦听器以侦听MouseEvent.CLICK 事件。最后,代码为舞台的目标阶段和冒泡阶段注册了clickListener()侦听器以侦听MouseEvent.CLICK 事件。
当 clickListener()执行,他会输出当前阶段。注意当前阶段是由比较eventPhase 和EventPhase 类的3种常量属性来确定的。
点击文本的时候显示:(因为注册了2次所以在捕获和冒泡都调用)
Current event phase: Capture
Current event phase: Bubbling
点击舞台其他空白地方时候显示:
Current event phase: Target
下一节将讨论到, eventPhase属性代表性地用来区分目标指向对象的事件和目标指向对象的子级的事件。还可以通过在捕获阶段和冒泡阶段注册父级侦听器后,使用eventPhase区分这2个阶段。
21.6. 区分目标指向对象的事件和目标指向对象的子级对象的事件
如果传递给侦听器的Event 对象的eventPhase属性是EventPhase.AT_TARGET,我们就知道这个事件发送是以被注册了侦听器的对象为目标的。而当eventPhase是EventPhase.CAPTURING_PHASE 或者EventPhase.BUBBLING_PHASE, 我们就知道这个事件的目标是被注册了侦听器的对象的子级对象。
因此,一个被注册了侦听器函数的对象可以使用如下代码来忽略指向他的子级对象的事件:
private function someListener (e:SomeEvent):void {
if (e.eventPhase == EventPhase.AT_TARGET) {
// 这里的代码只为目标指向该对象自身的事件而执行
}
}
我们可以使用前面的方法来书写代码来响应一个给定的对象接收到的输入,而不是它的子级对象.。比如,假设有一个应用程序,它的Stage 实例包含了大量的按钮、文本框已经其他一些可以接受用户输入的对象。现在要响应仅仅发生在Stage上的鼠标点击事件,我们像这样:
//为舞台实例注册MouseEvent.CLICK事件.
// 我们需要clickListener()函数忽略所有在显示列表其他位置发生的鼠标点击事件
stage.addEventListener(MouseEvent.CLICK, clickListener);
// ...在别处,定义MouseEvent.CLICK 事件侦听器
private function clickListener (e:MouseEvent):void {
// 如果这个侦听器只在目标阶段被调用...
if (e.eventPhase == EventPhase.AT_TARGET) {
// ...那么就是舞台实例被点击了,则进行“舞台被点击了”的响应代码
}
}
假如要创建一个事件侦听器,这个侦听器忽略以被注册了侦听的对象自身为目标的事件,只对它的子级对象发生的事件做出响应,我们可以这样:
private function someListener (e:SomeEvent):void {
if (e.eventPhase != EventPhase.AT_TARGET) {
// 这里的代码仅仅当被注册侦听的对象的子级对象发生事件而执行
}
}
比如,下面的侦听器只对在显示列表任何位置除了空白舞台上发生的鼠标点击做出响应
// 为舞台实例注册 MouseEvent.CLICK events
stage.addEventListener(MouseEvent.CLICK, clickListener);
// ...在其他地方,定义MouseEvent.CLICK 事件侦听器
private function clickListener (e:SomeInputEvent):void {
// 如果这个侦听器不在目标阶段执行...
if (e.eventPhase != EventPhase.AT_TARGET) {
// ...那么事件的目标就应该是舞台实例的其他子级对象.
//因此,鼠标肯定是点击了显示列表的除了STAGE的其他位置
}
}