这一阵一直在研究有关MX2004的组件开发的相关内容,找到不少不错的相关文章,不敢独享,先翻译一篇有关事件模型的供大家共同学习。
第一次做翻译工作,呵呵,难免有出错的地方,尽请各位指正!
The V2 Component Event Model Part 1- EventDispatcher
作者:Philter 翻译:xiankevin
当花了一些时间熟悉V2组件的事件模型之后,我觉得可以写一些自己的心得,当然更希望对别人有用。
V2组件的事件模型是基于监听器(listener),而不是像V1中基于回调函数(callbacks)。
在Flash MX的V1组件中,比如你可以使用”setClickHandler”将一个函数注册(register):为当组件被点击的时候调用的回调函数。你需要指定包含着个函数的对象,如果你没有指定,Flash会自动在组件的_parent范围内查找这个函数。但这种方法有一些小的局限,因为你必须有让事件触发时调用的一段代码,并且给所有的相应的目标发送这个消息。
Flash MX实际上有一个内建机制用于实现事件监听,就是ASBroadcaster。这是一个允许你快速建立一个事件广播模型的内部对象(mm的帮助文档并没有提到),提供了添加、移除监听对象,并对这些对象广播事件的方法。但被发现存在一些小bug,导致”only every second eventhandler being called, if listeners are removed in the eventhandler”(不是很理解,汗!)。其他也还有另外一些用于克服这个缺点的基于监听器的事件模型。
Flashplayer7仍然支持ASBroadcaster,在将影片导出为Flashplayer7版本的swf时,似乎也修正了这个bug。但注意在Flash MX 2004是AsBroadcaster,这里s小写!
上面扯了这么多目的是引出下面这些——
V2组件实现了一个不用到AsBroadcaster的监听器模型。就是EventDispatcher类(位置在安装文件夹\en\First Run\Classes\mx\events下),用于给UIObject(是所有组件的基础)添加事件广播(在2004中称为”分派(dispatch)”)功能。它与AsBroadcaster的工作方式在本质上是相同的。
1) 通过调用EventDispatcher.initialize(dispathingObj)建立一个分派器对象。
2) 调用dispatchingObj.addEventListener(“event”,listeringObj)和
dispatchingObj.removeEventListener(listeningObj)来添加、移除一个监听器。
3) 调用dispatchingObj.dispatchEvent(eventObj)为这些监听器分派(广播)事件。
有一些细节需要注意:
1) 看起来似乎EventDispatcher基于被注册监听的事件的类型将监听器加以分类。而据我所知Asbroadcaster仅仅将所有的监听器依附于一个监听器组,并为所有监听器广播所有事件——如果一个监听器没有设置特定的事件处理方法则默认事件广播失败。EventDispatcher实际上为每个事件创建了各自的监听器组。这样,当一个特定的事件被分派时,仅仅查找此事件相关的监听器组。这是一个细节的,也是一个重大的差别!
2) 当通过EventDispatcher分派事件时,仅仅传递了一个包含所有你想要传递给监听器内容的属性的”事件对象(event object)”而不是像之前一样需要传递此事件与一大堆的参数。这个对象的一些重要属性有:
“type”-必需的属性,指明你分派的事件。
“target”-可选的属性,允许你向监听器的处理函数中传递一个对象的引用。如果未指明,则默认指向你的分派器对象。
3) 在你的dispatcher传递被事件监听器调用的该事件之前,实际上会先调用一个内部的方法(有些像V1组件中的”click handler”),这让你如果需要可以使dispatcher对它本身做一些处理(所以类似V1组件中的回调模型)。使用这个功能,你需要在你的分派器对象中定义一个以[事件名+”Handler”]命名的方法,比如如果有一个click事件,则应定义为”clickHandler”。它将传递2)中提到的事件对象。
4) dispatcher可以接受Object、MovieClip或者单纯的函数(function)作为监听器。当你使用它们作为监听器的时候,还是会有稍许的差别:
如果使用Object、MovieClip建立监听器,则有两种方法来捕获事件:
a) 在Object或者MovieClip上定义一个与所监听的事件同名的方法。例如,监听click事件,则应建立myObj.click=function(eventObj){//…};
b) 在Object或者MovieClip上定义一个”handlerEvent(eventObj)”。它将成为一个类的接口(interface),通过它你的监听器可以处理相应被分派的事件(event dispatches)。所有被分派的事件都会传出这个方法,也就意味着你必须察看eventObj.type才能知道具体是哪个事件被触发并且执行相应的代码。
那么在使用组件时具体应该如何做呢?这里给出一个简单的例子。假设场景中有一个Button组件,名为”submitBtn”,你应该这样做以建立一个监听器对象:
// Listening object contains a function with the same name as
// the dispatched event
var listeningObj:Object = new Object();
listeningObj.click = function(eventObj:Object):Void {
trace("submitted by " + eventObj.target);
}
submitBtn.addEventListener("click",listeningObj);
或者这样:
// Use a central "handleEvent" function to mitigate all events
var listeningObj:Object = new Object();
listeningObj.handleEvent = function(eventObj:Object):Void {
if (eventObj.type == "click") {
trace("submitted by " + eventObj.target);
}
}
submitBtn.addEventListener("click",listeningObj);
或者像V1组件中一样:
// Old school click handler style
submitBtn.clickHandler = function():Void {
trace("submitted by " + this);
}
另外,使用一个普通的函数作为监听器。假设你想要从不同的分派对象监听相同的事件,如果已经建立了包含click方法的监听对象,那么要区分具体是哪个dispatcher分派的事件的唯一的办法就是察看传递的eventObj的target属性。但如果你定义一系列函数作为监听器,你就可以为任何被分派的事件指定具体如何执行。
// Use plain functions as listeners and specify which one
// you want to listen for any given event from any given
// dispatcher
function handleSubmit = function(eventObj:Object):Void {
trace("submitted!");
}
function handleReset = function(eventObj:Object):Void {
trace("reset!");
}
submitBtn.addEventListener("click",handleSubmit);
resetBtn.addEventListener("click",handleReset);
当然你也可以通过为每个dispatcher建立一个对象完成相同的任务。
在今后我还会介绍关于UIEventDispatcher和LowLevelEvent的内容,敬请关注。
全文完。