AS3事件处理模型
一直忙,却不知道在忙啥,难得有空自己看看这部分内容,分享一下
以前的事件处理模型:
as3有什么不同:
全部废除,只有addEventListener()一种了
listener只可以是methods或function,而且自带了Delegate(好多资料里都有写,这点就不讨论了)
多了event flow概念,就是说as2中只有广播者才能addEventListener,as3中即使object不发广播,只要它在event flow中都可以 addeventlistener
event flow:
事件源如果不在displaylist中,那么跟as2一样只能 事件源.addEventListner("xxx" xxxfunc)
否则如果事件源是可视的,那么Flashplayer会把这个event object扔到事件源所处的displaylist中去
displaylist 是一个树型结构,可以想象为下图
,然后这个eventObject会自己旅游到事件源那去,然后再回来
event flow 就是描述eventObject在这个displaylist中的旅游过程
顶端是一个特殊的display object容器---- Stage,他表现在flash.display.Stage类中,然后每一个display object都有一个属性叫stage 都引用这个应用程序的Stage
event flow 概念上被分为3部分。
第一部分叫 capture 阶段 包括从Stage到目标的parent
第2 部分叫 target 阶段 就只有目标节点
地3 部分叫 bubbling 阶段 包括从目标的parent到Stage
如图:
前边说过如果事件源不在displaylist中,那么跟as2一样只能 事件源.addEventListner("xxx" xxxfunc) 因为它就只参加 target阶段,1,3阶段都不参与
一些特殊的事件也是这样,例如enterFrame 和 init
否则该eventObject将参与这3个阶段
但在一般情况下,默认的addEventListener只监听event flow第 2,3阶段。
看个鼠标点击的例子
(点此下载)
mc里放mc1,点击mc1
e.eventPhase返回 1,2或3,分别代表上边说的3个阶段, 上边的意思就是在event flow第3个阶段捕捉到的这个事件
流程是这样滴:
当你点mc1 目标节点就被设置为mc1
然后Flashplayer 就扔出一个eventobject到Stage
这个eo落地就开始跑,这个跑道就是Stage---> mc1 ---->Stage 这一圈
整个跑道会经过两次mc ,Stage---> mc1 经过一次 ,然后mc1 ---->Stage又经过一次,也就是第1阶段和第3阶段
mc.addEventListener("click",func) 默认只监听第2,3阶段,而经过mc的只有1,3阶段,所以这句话就是在整个跑道上第3阶段mc位置放个路障
eo向mc1跑, 然后从mc1返回Stage的徒中经过mc时候碰到了路障触发了这个事件,所以e.eventPhase显示是第3阶段 目标是mc1,路障是mc
如果想第一阶段就捕捉事件怎么做?
加个参数true,代表只捕捉第一阶段的事件
看,第一阶段就被障碍拦住了吧
如果想3个阶段都兼听呢?
麻烦点,得add两次了,设两个路障了
阻止event flow !
设个障碍还不行,还要阻止?
怎么样只捕捉了第1个阶段吧,
其实有两个方法可以阻止event flow,
e.stopPropagation()
e.stopImmediatePropagation()
区别就在于一个影响当前节点一个不影响当前节点的其他listener,具体看下边的例子
优先级(Event Priority)
同一个事件有很多listeners,这些listeners收到消息也有个先后顺序,顺序默认是你add Listener时的顺序,如下边例子,completeListenerA肯定在completeListenerB 前执行
但是这个顺序是可以改变的,这就是我们的优先级要做的了。
addEventListener(type, listener, useCapture, priority, useWeakReference)
优先级默认是0 ,优先级越大,越先收到到广播。
下边的例子强行指定completeListenerB在completeListenerA之前执行
优先级很有用,比如可以设置一个高优先级的listener来初始化应用程序,使其他listener在初始化之前没有机会执行
或者用高优先级的listener来阻止事件发送,使其他listener接收不到
虽然优先级很有用,但是一定要尽量不用,因为优先级是可变的,你依赖他的执行顺序会使得代码它difficult to maintain,and make source
code more difficult to follow.
弱引用:
The concept of weak references is particularly useful when adding listeners to objects. To understand why weak references are so good, you first need to understand a little about garbage collection. Garbage collection is how Flash Player cleans up memory that isn't needed anymore; it's important because otherwise applications would use more and more RAM until they required the system to restart. Flash Player 9 uses two systems called reference counting and mark and sweep.
Reference counting is not new to Flash Player. It is the traditional way in which Flash Player has run garbage collection. When you create an object in ActionScript, that object exists in memory. However, the object is useful only as long as there are references (such as variables) to that object. When no more references exist, it is safe to assume that the object is no longer used and can be garbage collected. Although this system is efficient, it is not accurate because it is possible, through circular references, to have references still in existence even though none of the references is actually accessible. For example, two objects can have references to one another. If the references to those objects are deleted, we would expect that the objects themselves would be garbage collected. However, because they have references to one another, they remain in memory.
The mark-and-sweep garbage collection system solves the circular reference problem by traversing all active (accessible) nodes within an application. Any objects that exist outside of the active nodes can be assumed to be no longer in use, and they can be garbage collected.
Although the two garbage collection systems work in conjunction to efficiently and effectively manage memory usage, they do not compensate for incorrect programming. It's important that you always remove event listeners when you no longer need to use them. If you register an event listener using normal references, it will not get garbage collected even if you delete the listener or the object containing the listener because the event dispatcher will still have a reference to it. Removing the event listener using removeEventListener() ensures that the event target no longer has a reference to the listener, and that action will allow it to be properly garbage collected after you've deleted the listener.
However, sometimes we can't remove the listeners because our object is deleted elsewhere. This is where weak references come in handy. They allow for normal event listening functionality, but when the listener object is removed, the listener is removed from memory properly because the reference is weak and not counted by the reference counting function of the garbage collector.
You can specify that a listener should use a weak reference by registering it using a value of true for the fifth parameter to the addEventListener() method.
target.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
阻止事件默认行为(preventDefault)
有些事件有默认的行为,我们可以阻止这些默认行为,例如下边的TextEvent.TEXT_INPUT事件发生时我们阻止了字母显示在文本框里这一默认行为,而把x放了进去
以前的事件处理模型:
on() 在 Button 或 MovieClip上的
onClipEvent() 直接写在 MovieClip instances 上的
Callback 函数 例如XML.onload 和 Camera.onActivity
addListener()方法 简单的事件监听
The UIEventDispatcher class 实现了部分 DOM event model.
onClipEvent() 直接写在 MovieClip instances 上的
Callback 函数 例如XML.onload 和 Camera.onActivity
addListener()方法 简单的事件监听
The UIEventDispatcher class 实现了部分 DOM event model.
as3有什么不同:
全部废除,只有addEventListener()一种了
listener只可以是methods或function,而且自带了Delegate(好多资料里都有写,这点就不讨论了)
多了event flow概念,就是说as2中只有广播者才能addEventListener,as3中即使object不发广播,只要它在event flow中都可以 addeventlistener
event flow:
事件源如果不在displaylist中,那么跟as2一样只能 事件源.addEventListner("xxx" xxxfunc)
否则如果事件源是可视的,那么Flashplayer会把这个event object扔到事件源所处的displaylist中去
displaylist 是一个树型结构,可以想象为下图
,然后这个eventObject会自己旅游到事件源那去,然后再回来
event flow 就是描述eventObject在这个displaylist中的旅游过程
顶端是一个特殊的display object容器---- Stage,他表现在flash.display.Stage类中,然后每一个display object都有一个属性叫stage 都引用这个应用程序的Stage
event flow 概念上被分为3部分。
第一部分叫 capture 阶段 包括从Stage到目标的parent
第2 部分叫 target 阶段 就只有目标节点
地3 部分叫 bubbling 阶段 包括从目标的parent到Stage
如图:
前边说过如果事件源不在displaylist中,那么跟as2一样只能 事件源.addEventListner("xxx" xxxfunc) 因为它就只参加 target阶段,1,3阶段都不参与
一些特殊的事件也是这样,例如enterFrame 和 init
否则该eventObject将参与这3个阶段
但在一般情况下,默认的addEventListener只监听event flow第 2,3阶段。
看个鼠标点击的例子
![](http://www.nshen.net/blog/styles/default/images/icon_file.gif)
mc里放mc1,点击mc1
mc.addEventListener("click",func)
function func(e){
trace(e.target.name,"------",e.currentTarget.name)
trace("e.eventPhase",e.eventPhase)
}
/*----------------------out put----------
mc1 ------ mc
e.eventPhase 3
---------------------------------------*/
function func(e){
trace(e.target.name,"------",e.currentTarget.name)
trace("e.eventPhase",e.eventPhase)
}
/*----------------------out put----------
mc1 ------ mc
e.eventPhase 3
---------------------------------------*/
e.eventPhase返回 1,2或3,分别代表上边说的3个阶段, 上边的意思就是在event flow第3个阶段捕捉到的这个事件
流程是这样滴:
当你点mc1 目标节点就被设置为mc1
然后Flashplayer 就扔出一个eventobject到Stage
这个eo落地就开始跑,这个跑道就是Stage---> mc1 ---->Stage 这一圈
整个跑道会经过两次mc ,Stage---> mc1 经过一次 ,然后mc1 ---->Stage又经过一次,也就是第1阶段和第3阶段
mc.addEventListener("click",func) 默认只监听第2,3阶段,而经过mc的只有1,3阶段,所以这句话就是在整个跑道上第3阶段mc位置放个路障
eo向mc1跑, 然后从mc1返回Stage的徒中经过mc时候碰到了路障触发了这个事件,所以e.eventPhase显示是第3阶段 目标是mc1,路障是mc
如果想第一阶段就捕捉事件怎么做?
加个参数true,代表只捕捉第一阶段的事件
mc.addEventListener("click",func,true)
function func(e){
trace(e.target.name,"------",e.currentTarget.name)
trace("e.eventPhase",e.eventPhase)
}
/*----------------------out put----------
mc1 ------ mc
e.eventPhase 1
//---------------------------------------*/
function func(e){
trace(e.target.name,"------",e.currentTarget.name)
trace("e.eventPhase",e.eventPhase)
}
/*----------------------out put----------
mc1 ------ mc
e.eventPhase 1
//---------------------------------------*/
看,第一阶段就被障碍拦住了吧
如果想3个阶段都兼听呢?
麻烦点,得add两次了,设两个路障了
mc.addEventListener("click",func,true)
mc.addEventListener("click",func)
function func(e){
trace(e.target.name,"------",e.currentTarget.name)
trace("e.eventPhase",e.eventPhase)
}
/*----------------------out put----------
mc1 ------ mc
e.eventPhase 1
mc1 ------ mc
e.eventPhase 3
---------------------------------------*/
mc.addEventListener("click",func)
function func(e){
trace(e.target.name,"------",e.currentTarget.name)
trace("e.eventPhase",e.eventPhase)
}
/*----------------------out put----------
mc1 ------ mc
e.eventPhase 1
mc1 ------ mc
e.eventPhase 3
---------------------------------------*/
阻止event flow !
设个障碍还不行,还要阻止?
mc.addEventListener("click",func,true)
mc.addEventListener("click",func)
function func(e){
trace(e.target.name,"------",e.currentTarget.name)
trace("e.eventPhase",e.eventPhase)
e.stopPropagation()
}
/*----------------------out put----------
mc1 ------ mc
e.eventPhase 1
---------------------------------*/
mc.addEventListener("click",func)
function func(e){
trace(e.target.name,"------",e.currentTarget.name)
trace("e.eventPhase",e.eventPhase)
e.stopPropagation()
}
/*----------------------out put----------
mc1 ------ mc
e.eventPhase 1
---------------------------------*/
怎么样只捕捉了第1个阶段吧,
其实有两个方法可以阻止event flow,
e.stopPropagation()
e.stopImmediatePropagation()
区别就在于一个影响当前节点一个不影响当前节点的其他listener,具体看下边的例子
mc.addEventListener("click",func,true)
mc.addEventListener("click",func)
mc.addEventListener("click",func2,true)
mc.addEventListener("click",func2)
function func(e){
e.stopPropagation()
//e.stopImmediatePropagation() //换换看看区别
trace(e.target.name,"------",e.currentTarget.name)
trace("e.eventPhase",e.eventPhase)
}
function func2(e){
trace(e.target.name,"--22222--",e.currentTarget.name)
trace("2222222e.eventPhase",e.eventPhase)
}
mc.addEventListener("click",func)
mc.addEventListener("click",func2,true)
mc.addEventListener("click",func2)
function func(e){
e.stopPropagation()
//e.stopImmediatePropagation() //换换看看区别
trace(e.target.name,"------",e.currentTarget.name)
trace("e.eventPhase",e.eventPhase)
}
function func2(e){
trace(e.target.name,"--22222--",e.currentTarget.name)
trace("2222222e.eventPhase",e.eventPhase)
}
优先级(Event Priority)
同一个事件有很多listeners,这些listeners收到消息也有个先后顺序,顺序默认是你add Listener时的顺序,如下边例子,completeListenerA肯定在completeListenerB 前执行
package {
import flash.display.*;
import flash.net.*;
import flash.events.*;
public class FileLoader extends Sprite {
public function FileLoader ( ) {
var urlLoader:URLLoader = new URLLoader( );
// Registration order determines execution order
urlLoader.addEventListener(Event.COMPLETE, completeListenerA);
urlLoader.addEventListener(Event.COMPLETE, completeListenerB);
urlLoader.load(new URLRequest("someFile.txt"));
}
private function completeListenerA (e:Event):void {
trace("Listener A: Load complete");
}
private function completeListenerB (e:Event):void {
trace("Listener B: Load complete");
}
}
}
import flash.display.*;
import flash.net.*;
import flash.events.*;
public class FileLoader extends Sprite {
public function FileLoader ( ) {
var urlLoader:URLLoader = new URLLoader( );
// Registration order determines execution order
urlLoader.addEventListener(Event.COMPLETE, completeListenerA);
urlLoader.addEventListener(Event.COMPLETE, completeListenerB);
urlLoader.load(new URLRequest("someFile.txt"));
}
private function completeListenerA (e:Event):void {
trace("Listener A: Load complete");
}
private function completeListenerB (e:Event):void {
trace("Listener B: Load complete");
}
}
}
但是这个顺序是可以改变的,这就是我们的优先级要做的了。
addEventListener(type, listener, useCapture, priority, useWeakReference)
优先级默认是0 ,优先级越大,越先收到到广播。
下边的例子强行指定completeListenerB在completeListenerA之前执行
package {
import flash.display.*;
import flash.net.*;
import flash.events.*;
public class FileLoader extends Sprite {
public function FileLoader ( ) {
var urlLoader:URLLoader = new URLLoader( );
// Priority parameter determines execution order
urlLoader.addEventListener(Event.COMPLETE,
completeListenerA,
false,
0);
urlLoader.addEventListener(Event.COMPLETE,
completeListenerB,
false,
1);
urlLoader.load(new URLRequest("someFile.txt"));
}
private function completeListenerA (e:Event):void {
trace("Listener A: Load complete");
}
private function completeListenerB (e:Event):void {
trace("Listener B: Load complete");
}
}
}
import flash.display.*;
import flash.net.*;
import flash.events.*;
public class FileLoader extends Sprite {
public function FileLoader ( ) {
var urlLoader:URLLoader = new URLLoader( );
// Priority parameter determines execution order
urlLoader.addEventListener(Event.COMPLETE,
completeListenerA,
false,
0);
urlLoader.addEventListener(Event.COMPLETE,
completeListenerB,
false,
1);
urlLoader.load(new URLRequest("someFile.txt"));
}
private function completeListenerA (e:Event):void {
trace("Listener A: Load complete");
}
private function completeListenerB (e:Event):void {
trace("Listener B: Load complete");
}
}
}
优先级很有用,比如可以设置一个高优先级的listener来初始化应用程序,使其他listener在初始化之前没有机会执行
或者用高优先级的listener来阻止事件发送,使其他listener接收不到
虽然优先级很有用,但是一定要尽量不用,因为优先级是可变的,你依赖他的执行顺序会使得代码它difficult to maintain,and make source
code more difficult to follow.
弱引用:
The concept of weak references is particularly useful when adding listeners to objects. To understand why weak references are so good, you first need to understand a little about garbage collection. Garbage collection is how Flash Player cleans up memory that isn't needed anymore; it's important because otherwise applications would use more and more RAM until they required the system to restart. Flash Player 9 uses two systems called reference counting and mark and sweep.
Reference counting is not new to Flash Player. It is the traditional way in which Flash Player has run garbage collection. When you create an object in ActionScript, that object exists in memory. However, the object is useful only as long as there are references (such as variables) to that object. When no more references exist, it is safe to assume that the object is no longer used and can be garbage collected. Although this system is efficient, it is not accurate because it is possible, through circular references, to have references still in existence even though none of the references is actually accessible. For example, two objects can have references to one another. If the references to those objects are deleted, we would expect that the objects themselves would be garbage collected. However, because they have references to one another, they remain in memory.
The mark-and-sweep garbage collection system solves the circular reference problem by traversing all active (accessible) nodes within an application. Any objects that exist outside of the active nodes can be assumed to be no longer in use, and they can be garbage collected.
Although the two garbage collection systems work in conjunction to efficiently and effectively manage memory usage, they do not compensate for incorrect programming. It's important that you always remove event listeners when you no longer need to use them. If you register an event listener using normal references, it will not get garbage collected even if you delete the listener or the object containing the listener because the event dispatcher will still have a reference to it. Removing the event listener using removeEventListener() ensures that the event target no longer has a reference to the listener, and that action will allow it to be properly garbage collected after you've deleted the listener.
However, sometimes we can't remove the listeners because our object is deleted elsewhere. This is where weak references come in handy. They allow for normal event listening functionality, but when the listener object is removed, the listener is removed from memory properly because the reference is weak and not counted by the reference counting function of the garbage collector.
You can specify that a listener should use a weak reference by registering it using a value of true for the fifth parameter to the addEventListener() method.
target.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
阻止事件默认行为(preventDefault)
有些事件有默认的行为,我们可以阻止这些默认行为,例如下边的TextEvent.TEXT_INPUT事件发生时我们阻止了字母显示在文本框里这一默认行为,而把x放了进去
package {
import flash.display.*;
import flash.text.*;
import flash.events.*;
// Changes all user-entered text to the character "x"
public class InputConverter extends Sprite {
private var t:TextField;
public function InputConverter ( ) {
// Create the text field
t = new TextField( );
t.border = true;
t.background = true;
t.type = TextFieldType.INPUT
addChild(t);
// Register for the TextEvent.TEXT_INPUT event
t.addEventListener(TextEvent.TEXT_INPUT, textInputListener);
}
// Listener executed when the TextEvent.TEXT_INPUT event occurs
private function textInputListener (e:TextEvent):void {
// Show what the user tried to enter
trace("Attempted text input: " + e.text);
// Stop the user-entered text from appearing in the text field
e.preventDefault( );
// Add the letter "x" to the text field instead of
// the user-entered text
t.appendText("x");
}
}
}
import flash.display.*;
import flash.text.*;
import flash.events.*;
// Changes all user-entered text to the character "x"
public class InputConverter extends Sprite {
private var t:TextField;
public function InputConverter ( ) {
// Create the text field
t = new TextField( );
t.border = true;
t.background = true;
t.type = TextFieldType.INPUT
addChild(t);
// Register for the TextEvent.TEXT_INPUT event
t.addEventListener(TextEvent.TEXT_INPUT, textInputListener);
}
// Listener executed when the TextEvent.TEXT_INPUT event occurs
private function textInputListener (e:TextEvent):void {
// Show what the user tried to enter
trace("Attempted text input: " + e.text);
// Stop the user-entered text from appearing in the text field
e.preventDefault( );
// Add the letter "x" to the text field instead of
// the user-entered text
t.appendText("x");
}
}
}