注意:本文参考An introduction to AS3 Signals写成,但不是翻译,有增删改。
- 第一部分:Signals框架介绍(一)基本用法
- 第三部分:Signals框架介绍(三)原生事件
也许你现在又想起了AS3内置事件框架的好处,希望使用currentTarget?或者希望支持冒泡?OK,Signals也能满足你那多变的心……(貌似是我自己多变罢了ˇ^ˇ)
高级事件
使用DeluxeSignal可以实现更高级的事件传递。还是基于闹钟的例子进行修改,将原来AlarmClock中的Signal改为DeluxSignal:
[AlarmClock.as]
public function AlarmClock() { //将自己作为引用传递给DeluxeSignal,同时增加GenericEvent的传递 alarm = new DeluxeSignal(this, GenericEvent, Date); } public var alarm:DeluxeSignal; public function ring():void { alarm.dispatch(new GenericEvent(), new Date()); } |
修改Wakeup.as中的处理器函数,让它能够接受到传递的2个参数。
[Wakeup.as]
private function handler_ring($evt:GenericEvent, $date:Date):void { trace('currentTarget:',$evt.currentTarget); trace('target:',$evt.target); trace('signal:',$evt.signal); trace('起床了!!!也不看看几点了:'+$date.toString()); } |
在这里出现的GenericEvent,并非继承自flash.events.Event,而是实现了Signals自己的IEvent接口,与AS3的事件机制毫无关系。取一个貌似兄弟的名称,是为了方便大家理解罢了。它所提供的currentTarget和target属性,也是由IEvent自身提供。
运行修改后的例子,可以看到如下输出:
[trace] currentTarget: [object AlarmClock]
[trace] target: [object AlarmClock]
[trace] signal: [object DeluxeSignal]
[trace] 起床了!!!也不看看几点了:Mon Jan 23 17:07:16 GMT+0800 2012
现在,是不是可以对currentTarget“为所欲为”了呢?
冒泡事件
Signals一样可以冒泡,而且并不依赖AS3自带的事件机制。当然,发送和接收冒泡事件的对象必须处于显示列表中。
为了让AlarmClock能够被加入显示列表,我们让AlarmClock继承Sprite。而抛出冒泡事件就非常简单,只需要在实例化GenericEvent的同时传递true参数即可。看看AlarmClock类被修改的部分吧:
[AlarmClock.as]
public class AlarmClock extends Sprite { public function ring():void { alarm.dispatch(new GenericEvent(true), new Date()); } } |
接收事件的类,必须实现IBubbleEventHandler接口,在onEventBubbled中处理冒泡事件。同时,要将\_alarm实例加入显示列表。
为了方便查看冒泡效果,可以将addOnce所在的一行注释掉,只接收冒泡事件。
[Wakeup.as]
public class Wakeup extends Sprite implements IBubbleEventHandler { public function Wakeup() { _alarm = new AlarmClock(); addChild(_alarm); //_alarm.alarm.addOnce(handler_ring); _alarm.ring(); } public function onEventBubbled($evt:IEvent):Boolean { trace('冒泡 currentTarget:',$evt.currentTarget); trace('冒泡 target:',$evt.target); trace('冒泡 signal:',$evt.signal); //返回false代表不再继续冒泡 return false; } } |
运行修改后的例子,可以看到如下输出:
[trace] 冒泡 currentTarget: [object Wakeup]
[trace] 冒泡 target: [object AlarmClock]
[trace] 冒泡 signal: [object DeluxeSignal]
完整的类
[AlarmClock.as]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package { import flash.display.Sprite; import org.osflash.signals.Signal; import org.osflash.signals.DeluxeSignal; import org.osflash.signals.events.GenericEvent; /** * Signals闹钟范例 * @author Aiden Tailor(http://www.developria.com/2010/10/an-introduction-to-as3-signals.html) * @author zrong(zengrong.net) */ public class AlarmClock extends Sprite { public function AlarmClock() { alarm = new DeluxeSignal(this, GenericEvent, Date); } public var alarm:DeluxeSignal; public function ring():void { //使用冒泡的方式发布闹钟的响铃事件 alarm.dispatch(new GenericEvent(true), new Date()); } } } |
[Wakeup.as]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package { import flash.display.Sprite; import org.osflash.signals.events.GenericEvent; import org.osflash.signals.events.IBubbleEventHandler; import org.osflash.signals.events.IEvent; [SWF(width=500,height=300,frameRate=30,backgroundColor=0xFFFFFF)] /** * 测试闹钟 * @author Aiden Tailor(http://www.developria.com/2010/10/an-introduction-to-as3-signals.html) * @author zrong(zengrong.net) */ public class Wakeup extends Sprite implements IBubbleEventHandler { public function Wakeup() { _alarm = new AlarmClock(); addChild(_alarm); _alarm.alarm.addOnce(handler_ring); _alarm.ring(); } private var _alarm:AlarmClock; private function handler_ring($evt:GenericEvent, $date:Date):void { trace('currentTarget:',$evt.currentTarget); trace('target:',$evt.target); trace('signal:',$evt.signal); trace('起床了!!!也不看看几点了:'+$date.toString()); } public function onEventBubbled($evt:IEvent):Boolean { trace('冒泡 currentTarget:',$evt.currentTarget); trace('冒泡 target:',$evt.target); trace('冒泡 signal:',$evt.signal); //返回false代表不再继续冒泡 return false; } } } |


使用此框架实现冒泡貌似比as3默认方式复杂,又要继承接口又要写固定的方法
在使用”onEventBubbled(evt:IEvent)”冒泡事件之后,此方法并不能直接传递参数,而使用handler_ring自定义方法又必须使用alarm.add/addOnce, 此时虽然可以使用静态对象来解决层级问题,但并不是最好的解决办法,在onEventBubbled里面写evt.signal.addOnce(handler_ring)也是无效的,似乎有点矛盾了
也许是它传递参数固定这个特性,所以想进行调用,还是必须直接引用此对象,所以大型开发的话,这个还是不能胜任,只能作为单个零件来使用
冒泡的实现其实并不比AS3本身Event机制复杂。你在使用Event机制不需要继承接口的原因,是你所有支持冒泡的类本身就继承了Sprite,Sprite继承自EventDispatcher,且实现了IEventDispatcher接口。
冒泡事件中确实不能传递参数,但可以通过存取currentTarget实现参数获取。
你可以将Signals搭配PureMVC或者Robotlegs等框架使用。
这样看来又有些复杂了。。
我想如果它的冒泡功能能传递参数的话再好不过了,因为通过冒泡本身是能够访问到发送事件的对象的,只需要修改支持立即处理指定方法就可以在传递过程中直接调用了
我写了个简单的鼠标单击加自定义事件的方法 来测试效率。发现他和原生事件的运行时间是一样的 可能是测试太简单了。无法展现这个框架所写的4倍效率。有没有什么好的测试方法做做比较。
这个性能我没有测试过,所以我用的“据说”。理论上讲,如果不考虑冒泡,性能确实会比AS3的内置机制高些。
你可以去看作者的源码,在他提供的项目中,有一个测试性能的项目。