先来看个例子:
地点:饭馆类(extend Sprite or UIcomponent...,是个容器就行)
人物:客人类(extend EventDispatcher,会说话就行)、厨师类(extend Object,能
满足客人需求就行)
一、四个步骤:注册侦听、分发事件、侦听事件、移除侦听。
(1)、注册侦听:客人进入饭馆,使用addEventListener指定某厨师准备做菜。
(2)、分发事件:客人使用dispatchEvent对厨师进行喊话,表示我要吃什么。喊话内
容被放在Event类或其子类里,主要包括类型、目标和数据三部分。类型(Type)就是点
菜,而不是结账,上酒水。目标(Target)用来记录是哪桌的客人。数据(Data)用来保
存重要信息,如果是点菜,那记的就是菜名。
(3)、侦听事件:根据注册侦听中的需求,厨师开始做菜。
(4)、移除侦听:不移除的后果就是,以后在任意餐馆里喊话叫菜,所有注册过侦听的
餐馆厨师都开始做菜。
一些细节:
(1)、为了方便客人类在饭馆类中使用MXML标签注册侦听,常常在客人类中使用Event
标签。比如[Event(name="onChange", type="components.MyEventTest")]
(2)、注册侦听时,可以使用弱引用,即更改addEventListener中的useWeakReference
属性的默认值false为true。这样垃圾回收器会检测弱引用侦听并自动移除,极其不建
议这样做,而是直接移除侦听。
(3)、当客人类已经继承了某类,无法再继承EventDispatcher时,可以考虑实现
IEventDispatcher接口。额外地,需要实现此接口定义的五个方法addEventListener
、dispatchEvent、willTrigger、removeEventListener和hasEventListener。当然,
在实现过程中,可以灵活地添加别的新特性。
二、事件流机制
(1)、捕获阶段:Flash Player会按照显示列表,从根容器舞台往下找,直到确定是哪
个桌的客人在喊话要菜。
(2)、目标阶段:捕获阶段结束时停在哪个目标对象上。
(3)、冒泡阶段:事件对象从目标对象再次沿显示列表往上移动至根容器舞台,遇到注
册侦听的节点就调用侦听函数。如果想中途中断冒泡,可以使用stopPropagation,详
见文末Event备注部分。
一些细节:
(1)、这三个阶段由Event中的eventPhase属性来记录,1表示捕获,2表示目标,3表示
冒泡。
(2)、目标阶段确定的目标对象由Event中的target属性来记录,冒泡阶段移动的游标
则由currentTarget来记录。事件对象每往上移动一级,就会克隆出一个仅与前副本
currentTarget不同的新副本。这也提示我们,在自定义Event类时,如果打开了冒泡
属性bubbles,则必须要覆盖原有的clone方法,否则在冒泡时就会丢失自定义的存储
数据。同样,最好也覆盖原有的toString方法。
(3)、侦听器的调用一般发生在冒泡阶段。但是当target等于currentTarget,也就是
当前侦听对象就是事件发生对象时,冒泡阶段就没有了,这时目标阶段就发生了侦听
器调用。如果希望在捕获阶段侦听事件,将addEventListener中的useCapture参数改
为true即可,这时冒泡阶段将不再发生侦听。如果希望仍在冒泡阶段继续侦听,需要
新添加一个useCapture为默认值false的侦听。
(4)、事件对象是否可以冒泡要看两点:第一,事件本身是否支持冒泡,由bubbles属
性设定,为true则支持,默认为false;第二,如果事件发生的对象不在显示列表中,
也不可能冒泡,此时只有目标阶段,如Timer和URLLoader。
(5)、显示列表下,某个容器中有两个并列子节点1和2。如果子节点1发出事件,需要
在子节点2中进行侦听,默认情况下是做不到的。常用的一种办法是向子节点1和子节
点2都传入一个相同的对象的实例,在子节点1中用这个对象实例发出事件,在子节点2
中用这个对象实例监听事件(在目标阶段捕获事件)。这样就可以收到字节点1的事件
了。
三、Event备注
属性:
bubbles:只读,布尔,事件是否开启冒泡功能
cancelable:只读,布尔,处理事件的默认行为是否可以停止。主要针对一些系统事
件,如果值为true,则Event的preventDefault方法可以使用,否则不可用。
currentTarget:只读,对象,当前正在调用监听器的对象
eventPhase:只读,整数,返回事件流正经历的阶段。1:捕获,2:目标,3:冒泡
target:只读,派发事件的目标对象
type:只读,字符,事件类型。比如鼠标点击事件的类型:click,并被定义为常量:
MouseEvent.CLICK
构造函数:
Event(
type:String, 事件类型
bubbles:Boolean = false, 是否冒泡
cancelable:Boolean = false 是否可以停止
)
方法:
isDefaultPrevented:判断preventDefault 是否已经被调用
preventDefault:停止事件的默认行为。针对一些系统事件,cancelable为true时才
可用。
stopImmediatePropagation:停止当前的事件流传播,包括当前正在处理的对象
stopPropagation:停止当前的事件流传播,但不会停止当前正在处理的对象
四、侦听器备注
addEventListener(
type:String, 事件的类型
listener:Function, 监听函数
useCapture:Boolean = false, 是否打开捕获功能
priority:int = 0, 监听器优先级别
useWeakReference:Boolean = false 是否使用弱引用
)
默认情况下,Flex会按照监听器注册的顺序来调用监听函数。使用addEventListener
函数的priority 来实现 监听函数的优先级。priority 为整数类型,数字越大,级别
越高。级别最高的最先被调用。已经存在的监听器,无法被修改优先级。使用MXML添
加的事件监听函数无法指定优先级别,将采用默认的级别。给一个对象注册多个监听
器,即使每个监听器的优先级别不同,但也无法保证后一个执行时前面的监听函数已
经执行完毕。设计时,后面的函数不应该以前者执行完毕为条件。