一:事件流机制
由于OOP编程将程序看成一个个对象、模块共同交流协作而提供功能或服务,这样必然会涉及对象之间交流消息的情况。所谓消息,就是指系统某处发生了什么事情,以信息的方式通知相关的对象。
AS3中采用的DOM3事件处理机制可以让交流数据的双方降低耦合度,及所谓的“脱耦”(脱离耦合性)!使得各个对象之间依赖性大大降低。
DOM3事件模型定义了一整套标准的生成和处理事件消息的方法,使程序中的对象可以相互交互、通信,保持自身状态和响应变化。
简单的说,数据的提供者只管发出数据对象,只要确保数据对象是flash.events.Event类或者子类的实例即可。
这种数据对象称为:事件(Event)。
数据对象的发出者称为:事件发送者(Event dispatcher)。
接受事件的对象称为:事件监听者(Event listener)。
DOM3事件的优点是:事件发送者和事件接收者的依赖性大大降低。
事件发送者只需要发送事件对象,
事件监听者只需要接受事件对象。
目标对象:派发事件的对象,是 Flash ® Player 事件模型的重要组成部分
每个事件对象都有以下属性:
target:事件的派发者
currentTarget:当前正在检测的的对象,帮助跟踪事件传播的过程。
当事件发生后生成一个携带数据的事件对象,Flash Player 会将事件对象调度到从显示列表根开始的事件流中然后该事件对象在显示列表中前进,检查目标对象是否存在显示层中,并遍历从根容器一直到目标对象所在位置的所有对象(以树形势表示),自动检测所经过的节点是否注册了监听器,直到到达事件目标,然后从这一点开始其在显示列表中的回程。
1:发生事件时,该事件在事件流的三个阶段中移动:
捕获阶段:该阶段从显示列表层次结构的顶部流动到目标节点之前的节点,检测每个节点是否注册了监听器,同时,Flex 将事件对象的currentTarget 值改为当前正在检测的对象。如果注册了监听器,则调用监听函数。
目标阶段:该阶段只包括目标节点;触发在目标对象本身注册的监听程序。
冒泡阶段:从目标节点到根节点,检测每个节点是否注册了监听器,如果有,则调用监听函数。
EventDispatcher 类实现 IEventDispatcher 接口,并且是 DisplayObject 类的基类。 EventDispatcher 类允许显示列表上的任何对象都是一个事件目标,同样允许使用 IEventDispatcher 接口的方法。
2:明确几个概念
(1、显示列表根:假如你有abc 三个panel c在b中 b在a中这样的嵌套关系 那么c-->b-->a
a就是列表的根
(2、目标:假如你在c上发了一个事件,那么c就是事件的目标。有些复杂控件(如Button)有click事件 不过发事件的目标不是它本身 那个currenttarget才是它本身
(3、事件传递的流程:首先你派发事件在c上 事件首先从a-->b-->c-->b-->a这样一个完整的循环
(4、捕获阶段:事件在a-->b的这个阶段(注意和b-->a不同)
(5、目标阶段 仅当事件到达c的时候
(6、冒泡阶段 b-->a这样经过的阶段
3、具体应用
当你在c上面派发了一个事件 然后你想在c的顶层a上监听到
你可能这么做
首先你在c上this.dispatchEvent(new Event("cevent",false)); 这样发了一个事件
蓝色字体 意味着这个事件只会在捕获和目标阶段 a->b->c ,那个参数属性表示是否打开冒泡
然后你在a上监听这个事件 a.addEventListener("cevent",function():void{trace("原始论坛目标发出的事件");},false);
红色字体 意味着你打算 让侦听器只在目标或冒泡阶段处理事件 就是c->b->a ,参数属性表示是否打开捕获
4、
任何一个false改成true就可以了
蓝色改成true意味着事件在所有过程传递
红色改成true意味着侦听捕获阶段
再简单说 新建事件(就是这个新建new Event("cevent",false))不冒泡 默认侦听只侦听冒泡
默认情况下,捕获功能处于关闭状态,一般没有必要进行捕获跟踪。
事件只在bubbles 属性为true 时才进行冒泡,可以冒泡的事件包括:change、click、doubleClick、keyDown、keyUp、mouseDown、 mouseUp。并且不能在一个监听器中同时打开捕获和冒泡功能,要做到这一点,只能注册两个监听器,分别实现。
看一个例子:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import flash.events.MouseEvent;
internal function initApp():void{
canvas_1.addEventListener(MouseEvent.CLICK,pressBtn,true);
canvas_2.addEventListener(MouseEvent.CLICK,pressBtn);
btn_1.addEventListener(MouseEvent.CLICK,pressBtn);
btn_2.addEventListener(MouseEvent.CLICK,pressBtn);
}
internal function output(msg:String):void{
debug_txt.text += msg+"/n";
}
internal function pressBtn(evt:MouseEvent):void{
output("是否冒泡--"+evt.bubbles);
output("目标对象-- "+evt.target+" -- "+evt.eventPhase);
output("遍历对象-- "+evt.currentTarget);
output("------------");
}
]]>
</mx:Script>
<mx:Canvas id = "canvas_1" styleName="box" x="37" y="63" width="445" height="216">
<mx:Text x="13" y="10" text="Canvas_1"/>
<mx:Canvas id="canvas_2" styleName="box" x="10" y="102" width="173" height="90">
<mx:Text x="10" y="10" text="Canvas_2"/>
<mx:Button id = "btn_2" x="10" y="38" label="Button_2"/>
</mx:Canvas>
<mx:Button id="btn_1" x="16" y="38" label="Button_1"/>
</mx:Canvas>
<mx:TextArea id="debug_txt" styleName="textBox" x="37" y="304" height="198" width="445"/>
</mx:Application>
二:addEventListener
上面的例子为例介绍:
在监听函数 pressBtn 中的属性说明:
addEventListener(
type:String, 事件的类型
listener:Function, 监听函数
useCapture:Boolean = false, 是否打开捕获功能。True表示捕获方式,false的话是冒泡
只有在特定状况下才会有影响,通常建议是false
priority:int = 0, 监听器优先级别
useWeakReference:Boolean = false 是否使用弱引用
)
addEventListener默认关闭了捕获阶段,打开冒泡阶段。并且捕获和冒泡阶段貌似是不能共存的。
没有捕获阶段(默认执行)具体是怎么执行的呢?
比如说有abc三个容器。同时对abc三个容器进行单击监听。
a.addEventListener(MouseEvent.CLICK,clickHandle);
b. addEventListener(MouseEvent.CLICK,clickHandle);
c. addEventListener(MouseEvent.CLICK,clickHandle);
我单击了c容器。
1、首先执行的是目标阶段。也就是我鼠标单击事件的目标是c容器,执行c容器的clickHandle函数。目标阶段完成。
2、冒泡阶段:将单击的事件冒泡上去,b获得了单击事件,执行clickHandle函数。然后就是c获得单击事件,执行clickHandle函数。
打开捕获
打开捕获阶段是怎么样的呢?
我单机了c容器。
1、捕获开始。a捕获到了单击事件执行函数。然后是b捕获到了单击事件执行函数。捕获阶段结束。
2、目标阶段开始。事件流终于流到了目标c,执行c的clickHandle函数。
总结:
1、捕获关闭后,顺序cba,由目标冒泡到父容器,一层一层上去。捕获打开后,顺序abc,由父容器一层一层下去直到目标事件。