AS3事件机制概述
事件机制是AS3的核心功能之一,没有充分掌握事件机制的方方面面,就不能算是精通AS3语言。
1. AS3事件机制的主要成员
IEventDispatcher:事件派发对象接口,定义了添加、派发、移除、是否监听指定事件、是否触发指定事件接口
EventDispatcher:事件派发对象接口的实现者,用户无法撇开EventDispatcher而自行实现IEventDispatcher接口,无法直接继承EventDispatcher时,必须把EventDispatcher作为实例变量。
Event:事件基类,所有事件类均基于此类实现
2. 观察者模式
AS3事件机制实现的是观察者模式。
IEventDispatcher充当了Subject角色,EventDispatcher相当于ConcreteSubject对象,Event相当于Observer,ConcreteSbserver相当于Event的子类。Attach相当于addEventListener,Detach相当于removeEventListener,Notify相当于dispatchEvent。Event没有Update。
3,显示列表中事件流的三个阶段
在一个事件的整个生命周期内,共分为三个阶段:
在捕获阶段与冒泡阶段均可能经过N个节点,在目标阶段仅可能有一个节点。
使用stopPropagation可阻止对事件流中当前节点的后续节点中的所有事件侦听器进行处理。使用stopImmediatePropagation可阻止对事件流中当前节点中和所有后续节点中的事件侦听器进行处理。
显示列表中事件流三阶段与事件机制本身没有直接关系。在AS3显示列表中,为什么要有事件流,为什么不是直接到达目标对象?
4,IEventDispatcher接口讲解
AS3事件机制的精髓基本全在这个接口中。
addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
使用 EventDispatcher对象注册事件侦听器对象,以使侦听器能够接收事件通知。
最常用的是前面二个参数。第三个参数标识该易做图是否会在捕获阶段被触发。第四个参数priority标识该同类事情易做图被调用的优化级。第五个参数标识该易做图是否易于被回收,默认为false,并且永远应该默认为false,如果易做图可以被回收,应该手动处理,而不是交给Flash Player。
对于监听同一类事件的易做图,priority高者优化被调用。在FP及Flex SDK中,priority最大不会超过200,因此,如果要设置top level的事件监听,此值应该设置在200以上。
在大型应用中,最好把各个层所要用到的priority分一下组,例如200-220分派给Core Level。
removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
从 EventDispatcher对象中删除侦听器。
如果在addEventListener时,useCapture为true,此时在removeEventListener时,useCapture参数应与之相同。EventDispatcher内部维护了两个listener集合,一个盛装useCapture为false的listener,另一个盛装为true的。
5,Event类实例化讲解
Event(type:String, bubbles:Boolean = false, cancelable:Boolean = false)
创建一个作为参数传递给事件侦听器的 Event对象。
Event 类的方法可以在事件侦听器函数中使用以影响事件对象的行为。某些事件有关联的默认行为。例如,doubleClick事件有关联的默认行为,此行为突出显示事件发生时鼠标指针下的词。通过调用 preventDefault()方法,您的事件侦听器可以取消此行为。通过调用 stopPropogation()或 stopImmediatePropogation()方法,还可以使当前事件侦听器成为要处理事件的最后一个事件侦听器。
cancelable标识该事件是否可阻止与取消。一般FP定义的内部事件类型均不可以取消,如CANCEL,CLOSE,OPEN,ADDED等,一般IMG事件均可以取消,如CLOSING,EXITING等,凡是可以取消的事件,均有一个关联的可以取消的行为。开发者在自定义事件也应遵守这一规则。
开发者应当保证type在应用程序中是唯一的,bubbles用于标识事件在到达目标对象后是否仍向下传递。
Event对象在事情流结束之后,如果没有其它引用,即可被GC回收。当前Event需要二次派发时,使用clone方法复制事件。
6,MouseEvent事件
鼠标事件是FP内InactiveObject对象内在支持的事件,这个事情由InactiveObject实例化、派发,并且总是bubble等于true的。对于不需要鼠标事件的对象,应当把mouseChildren与mouseEnabled设为flase,以优化程序性能。
7,Flash Player内部对事件的强力支持
FP本身是多线程的,只不过目前未对开发者开放API。在FP内部,有一个线程专门用于处理事件,事件的处理总是在桢周期的前期进行,并且不会受到其它线程的影响。
FP是异步的,Event的派发与listener的执行并不是紧密衔接的,当你派发一个事件之后,不能指望监听这个Event的Listener马上执行。
PureMVC放弃AS3内部支持的事情机制不用,自己用观察者模式实现了一套Command体系,是对FP中独立事件线程的非合理浪费。
8,事件与代的概念
在FP内部,从宏观上讲,总是派发一拔事件,处理一拔代码,然后再派发一拔事件,再处理一拔代码,如此反复,看起来事件具有代(generation)的概念。代与事件流有关,也与桢周期内的执行模式有关。
9,为什么要有事件流三阶段?
当用户在FP中单击时,宿主环境仅能告诉FP用户进行了单击行为以及单击的坐标,却并不能告诉FP到底单击了哪一个对象,哪一个MC,这是不可能的,因为是什么对象、有什么对象,只有FP自已知道。
在FP中,共有两种渲染模式,一种为保留模式,另一种为立即模式,无论是哪一种渲染模式,FP交给浏览器或操作系统的最终渲染内容总是一张张图片,FP像幻灯片放映一样向用户展示互动与动画。所以,当用户单击时,永远只是单击点,看得见的点,FP拿到这些点之后,在内部的显示列表结构上遍历,首先从上向下走,只要当前显示对象囊括了单击点,并且是透明的(下面还有显示对象),便一直往下走,直到目标对象,然后再原路一路向上走,这便是事件机制的三阶段。
由于显示对象可以是透明的,FP并不知道开发者设想的用户真正想单击的是不是目标对象,有可能是捕获阶段的对象,同样的对象也有可能想在冒泡阶段处理,为了提供更大的灵活性,FP在显示列表中实现了事件流的三步机制,数以千万开发者的实践证明它是非常有阶值的。
单击之外的其它鼠标事情与之类似。
10,优化程序性能的第一准则
及时移除不再需要的事情监听,是保证垃圾回收、优化程序性能的最浅显、最容易、最为开发者所忽视的行码准则之一。以下代码是通用的,在函数内部移除事件监听的方法:
e.currentTarget.removeEventListener(e.type, arguments.callee);
11,停止冒泡事情的派发
除了移除不必要的事情监听,停止冒泡事情的继续派发也是提高程序运行效率的常用方法之一。该方法多用于MouseEvent事情,代码为:
e.stopPropagation();
or
e.stopImmediatePropagation();
但是事情冒泡有时却是十分有用的,在某处阻止了事件冒泡,有可能因此另一处的监听无法触发,这种bug十分隐蔽。
AS3的事件流就三个阶段,捕获 >目标 > 冒泡
而在鼠标事件中,共有10种鼠标事件,分别如下:
点击事件: MouseEvent.CLICK ,MouseEvent.DOUBLE_CLICK
按键事件: MouseEvent.MOUSE_DOWN ,MouseEvent.MOUSE_UP
悬停事件: MouseEvent.MOUSE_OVER ,MouseEvent.MOUSE_OUT ,MouseEvent.ROLL_OVER ,MouseEvent.ROLL_OUT
移动事件: MouseEvent.MOUSE_MOVE
滚轮事件: MouseEvent.MOUSE_WHEEL
最令我不解的就是
悬停事件: MOUSE_OVER ,MOUSE_OUT ,ROLL_OVER ,ROLL_OUT
它们的具体工用是相似的
MOUSE_OVER = ROLL_OVER
MOUSE_OUT = ROLL_OUT
唯一不同的是前者参与事件流的冒泡阶段,而后者则不参加,
黑羽书上的例子类似,一个内部有文本框的按钮,
MOUSE_OVER ,MOUSE_OUT 事件中,鼠标移到按钮上,会触发over事件,当鼠标继续移,移到按钮里的文本上时,
就会触发文本的MOUSE_OVER事件,同一时间,按钮的MOUSE_OUT事件也会触发
而如果使用ROLL_OVER ,ROLL_OUT呢,这种情况下,鼠标移入按钮后,只要不移出按钮范围,按钮的OUT事件是不会触发的.
(________________________________
//括号内的内容为后期补充,实然是最终结果,建议先跳过看后面的,回头再看本段文字
此处我掉入了一个误区,不明白为什么移上子mc会触发移出事件,然后又触发移入事件,
其实不然,是事件流的原因,因为事件流机制默认是在冒泡阶段侦听的
所以整个流程解析就是,
1.先是鼠标移入按钮范围,触发按钮mc的①MOUSE_OVER事件,向上冒泡,没有其它对象侦听了,
2.鼠标继续移,移入内部影片剪辑a的范围时,触发mc的②MOUSE_OUT事件,同时又触发a的③MOUSE_OVER事件,
3.进入子影片剪辑a的冒泡阶段,因为a的父对象mc有侦听④MOUSE_OVER事件的,所以会触发mc的移入事件
4.鼠标移出a影片剪辑范围(仍未移出mc范围)时,触发a侦听的⑤MOUSE_OUT事件,
5.进入子影片剪辑a的冒泡阶段,触发mc的移出事件⑥MOUSE_OUT
6.鼠标重新移入到mc影片剪辑的范围,触发mc的⑦MOUSE_OVER事件
7.鼠标移出mc范围,触发mc的⑧MOUSE_OUT事件
//鼠标移入mc范围,未移入子影片剪辑a范围
//外部_移入_当前 mc _目标 mc mc的MOUSE_OVER生效①
//鼠标移入子影片剪辑a范围
//外部_移出_当前 mc _目标 mc mc的MOUSE_OUT生效②
//内部_移入_当前 a _目标 a mc.a的MOUSE_OVER生效③
//外部_移入_当前 mc _目标 a 冒泡阶段,mc的MOUSE_OVER生效④
//鼠标移出子影片剪
补充:综合编程 , 其他综合 ,