事件机制是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生效④

//鼠标移出子影片剪辑a范围
//内部_移出_当前 a _目标 a   mc.a的MOUSE_OUT生效⑤
//外部_移出_当前 mc _目标 a  冒泡阶段,mc的MOUSE_OUT生效⑥
//外部_移入_当前 mc _目标 mc mc的MOUSE_OVER生效⑦
//鼠标移出影片剪辑mc范围,回到舞台
//外部_移出_当前 mc _目标 mc mc的MOUE_OUT生效⑧

上面是trace出来的结果,下面是源代码,

场景中一个大影片剪辑mc,套一个小影片剪辑a
  复制内容到剪贴板

代码:

mc.a.addEventListener(MouseEvent.MOUSE_OVER,onFunA)
mc.a.addEventListener(MouseEvent.MOUSE_OUT,onFunB)
mc.addEventListener(MouseEvent.MOUSE_OVER,onFunC)
mc.addEventListener(MouseEvent.MOUSE_OUT,onFunD)
function onFunA(_evt:MouseEvent){
trace("内部_移入_当前www.shengshiyouxi.com",_evt.currentTarget.name,"_目标",_evt.target.name)
}
function onFunB(_evt:MouseEvent){
trace("内部_移出_当前",_evt.currentTarget.name,"_目标",_evt.target.name)
}
function onFunC(_evt:MouseEvent){
trace("外部_移入_当前",_evt.currentTarget.name,"_目标",_evt.target.name)
}
function onFunD(_evt:MouseEvent){
trace("外部_移出_当前",_evt.currentTarget.name,"_目标",_evt.target.name)
}

因为displayObject中 DisplayObjectContainer(容器)对象有一个属性mouseChildren,控制子显示对象是否接受事件,一般看到上面的话,而又知道mouseChildren属性的朋友,就会有疑问了(包括刚才的我),那这样我设显示对象的mouseChildren属性为false不就可以避免MOUSE_OUT事件在按钮内部触发了吗?
对了,这点黑羽在最后说明白了,在某些情况下,我们需要在子显示对象上写事件的,如果设了mouseChildren为false,则很不方便了.

最后,我对事件的冒泡过程不太明确,自己写了个小测试来验证了.
在场景中再一个矩形影片剪辑,实例名mc
双击进入后,再画一个矩形(稍小的),做成影片剪辑,实例名a
这样做成了一个父子套的关系,
然后写代码
  复制内容到剪贴板

代码:

mc.a.addEventListener(MouseEvent.CLICK,onFunA)
mc.addEventListener(MouseEvent.CLICK,onFunB)
function onFunA(_evt:MouseEvent){
trace(_evt.currentTarget.name,"_",_evt.target.name)
}
function onFunB(_evt:MouseEvent){
trace(_evt.currentTarget.name,"_",_evt.target.name)
}

运行,在单纯mc的范围上单击,返回的target是mc,currentTarget也是mc
输出结果:
mc _ mc
而如果鼠标再移入一点,在a影片剪辑上单击的时候,
事件流先到达目标阶段,触发a的侦听,然后冒泡阶段,再到mc
所以target一直是a,但currentTarget目标会在两次触发中分别为a(内层)和mc(外层)
输出结果:
a _ a
mc _ a
上面这个实验就是想证明自己的一个想法,冒泡事件是否触发的顺序是从底到顶的,上面的输出证实了这点理解.

这里可以返回上面看括号里的内容了,看完再接下面这段总结

总结:
1.事件流是面向DisplayObject的一个过程机制,但凡显示对象触发的事件,必有这个流过程,自上而下,再自下而上
2.事件流机制是在同一条路径上的父子关系的显示对象都会参与的(默认)
3.参与事件流的对象,对内部子对象,同样会触发MOUSE_OUT事件的
4.最重要的一点就是,子对象触发的事件,只要父对象有侦听,那么无论如何,父对象都会触发一次所侦听的事件
而且顺序是子对象先触发事件,然后父对象再触发(这是由冒泡阶段的顺序触发的)
5.将addEventListener函数中的第三个参数设为true,则只在捕获阶段侦听,对于没有子对象的元素,事件是不会触发的,只有当子对象同样侦听相同事件时,才会触发事件(因为没有目标阶段)
反正要理解事件机制,三个阶段的执行顺序及执行因素理解好后,下面的原理就很好理解了
如果设置addEventListener函数的第三个参数为true,会中断目标阶段的检测,但它始终会参加事件流,
所以ROLL_OVER和ROLL_OUT是实现不参加事件流(捕获和冒泡均不参加)操作的方法

呵呵,又加深了一点理解,开心ing.......

AS3事件机制概述的更多相关文章

  1. U3D C# 实现AS3事件机制

    写了很多年的AS3,最近接触U3D感觉事件机制没AS3的爽.咬紧牙关一鼓作气 基于C# 的委托实现了一版.废话不多说上干货. EventDispatcher代码如下: using UnityEngin ...

  2. [转]as3事件流机制彻底理解

    题记: 看过网上一些as3事件流的教程,觉得大多都讲得不甚清楚,让人不能直观的理解事件流.而这篇教程以将事件流过程比喻成捕鱼过程,形象简单. 在此基础上对于as3事件流总算有了全面的理解.事件流机制说 ...

  3. (转载)AS3.0实例学习 熟悉新的事件机制和addChild的运用

    (转载)http://www.jb51.net/article/13139.htm 首先声明:本人大菜鸟一个,刚接触AS3不久,许多理念还没来得及灌输,这些case都是从网上down的,但因为解说是英 ...

  4. Android广播机制概述

    1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器).广播作为Android组件间的通 ...

  5. ExtJs的事件机制Event(学员总结)

    一.事件的三种绑定方式 1.HTML/DHTML 在标签中直接增加属性触发事件 [javascript] view plaincopy <script type="text/javas ...

  6. Aa3.0 事件机制

    说明:本文由多处网络文章整理而成,在此未一一注明原文链接,敬请谅解! AS3:事件流机制  事件流 只要发生事件,Flash Player就会调度该事件对象. 如果事件目标不在显示列表中,则Flash ...

  7. 深入理解React:事件机制原理

    目录 序言 DOM事件流 事件捕获阶段.处于目标阶段.事件冒泡阶段 addEventListener 方法 React 事件概述 事件注册 document 上注册 回调函数存储 事件分发 小结 参考 ...

  8. 【移动端兼容问题研究】javascript事件机制详解(涉及移动兼容)

    前言 这篇博客有点长,如果你是高手请您读一读,能对其中的一些误点提出来,以免我误人子弟,并且帮助我提高 如果你是javascript菜鸟,建议您好好读一读,真的理解下来会有不一样的收获 在下才疏学浅, ...

  9. tkinter事件机制

    一.tkinter.Event tkinter的事件机制跟js是一样的,也是只有一个Event类,这个类包罗万象,集成了键盘事件,鼠标事件,包含各种参数. 不像java swing那种强类型事件,sw ...

随机推荐

  1. OS X 键盘快捷键

    了解有关常见 OS X 键盘快捷键的信息.键盘快捷键是通过按下键盘上的组合键来调用 OS X 功能的一种方式. 若要使用键盘快捷键或按键组合,您可以同时按修饰键和字符键.例如,同时按下 Command ...

  2. fragment中listview触发事件setOnItemClickListener不好使

    <listView/>中// listview点击 ,高度wrap_content改成fill_prarent

  3. Memcached管理与监控工具 memAdmin

    http://www.junopen.com/memadmin/ 使用MemCached以后,肯定希望知道cache的效果,对于MemCached的一些运行状态进行监控是必要的,memcached提供 ...

  4. Eclipse 快捷键操作和常用设置

    自动提示功能:一般的关键字,都有提示内容 像syso 就是System.out.println();for 循环 等 它的快捷键是 (Alt+/) 格式化代码: 有时候代码写多了 比较乱的话可以用快捷 ...

  5. ubuntu连接无线网

    我的ubuntu是因为没有安装无线网卡驱动,首先查看网卡型号 但是我在Broadcom官网上没有找到BCM43142的驱动. 通过谷歌后发现通过安装bcwl-kernel-source来解决这个问题, ...

  6. 普林斯顿大学算法课 Algorithm Part I Week 3 排序稳定性 Stability

    稳定性(Stability):先按性质A排序,再按性质B排序,性质B相同的那些项是否仍然是按性质A排序的? 一个稳定的排序,相同值的元素应仍保持相对顺序(relative order) 稳定的算法:插 ...

  7. iOS_根据文字字数动态确定Label宽高

    iOS7中用以下方法 CGSize 替代过时的iOS6中的- (CGSize)sizeWithFont:(UIFont *)font 方法 // iOS7_API_根据文字 字数动态确定Label宽高 ...

  8. 怎样调通微信支付及微信发货通知接口(Js API)

    怎样调通微信支付及微信发货通知接口(Js API) 微信支付提供了一个支付測试页面,微信支付正式使用须要測通支付.发货通知接口 .告警接口.维权接口.告警接口.维权接口非常easy.支付界面调通也相对 ...

  9. Android 它们的定义View (一)

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/24252901 非常Android入门程序员AndroidView.可能都是比較恐 ...

  10. varnish和squid的对比

    Varnish与Squid的对比  说到Varnish,不能不提Squid,Squid是一个高性能的代理缓存服务器,它和varnish之间有诸多的异同点,这里分析如下:  下面是他们之间的相同点:   ...