山寨版AS3事件冒泡机制的实现

AS3实现了事件传递,分成三段Capture,target和bubble,其中bubble就是向树根传递。这个机制非常之经典和好用,可惜它只存在在基于DisplayObject的对象树中,其它时候只能把事件老老实实的从一个对象直接传递到另一个对象。

这次我来玩个有趣的。仿造AS3内置的机制来制作一个更加通用的冒泡框架,相信可以用很多用处(至少已经用在我的项目上了)。自己实现事件传递,让它支持任何事件任何数据结构(无论队列,还是树),甚至可以传递任何对象(而不仅限于事件对象)。其实bubble的过程不难,就是把一个对象(特例就是事件对象)在一个链表里自动传递,不断的向上抛,过程跟AS3的事件机制别无二致。为了能扩展,我准备了接口和初步的实现类:IBubbleDispatcher和CBubbleDispatcher。跟IEventDIspatcher和EventDispatcher一样吧。来看看代码。

package org.gl.geom.abstract 
{
	import flash.events.Event;
 
	/**
	 * ...
	 * @author Jonson
	 */
	public interface IBubbleDispatcher 
	{
		/**
		 * add to bubble tree
		 * 
		 * @param	child
		 * @param	father
		 */
		function registerAsMyChild(child:IBubbleDispatcher):void;
 
		/**
		 * dispatch event, then bubble
		 * 
		 * @param	event
		 */
		function bubble(event:Event):void;
 
		/**
		 * it's better to be override in subclass
		 * 
		 * @param	event
		 * @return	true means continue bubble
		 */
		function myBubbleEventHandler(event:Event):Boolean
	}
 
}
package org.gl.geom.abstract 
{
	import flash.events.Event;
 
	/**
	 * ...
	 * @author Jonson
	 */
	public class BubbleDispatcher implements IBubbleDispatcher
	{
		//////////////////////////////////////////////////
		// render event bubble
 
		private var __my_parent__:IBubbleDispatcher;
 
		/**
		 * add to bubble tree
		 * 
		 * @param	child
		 * @param	father
		 */
		public function registerAsMyChild(child:IBubbleDispatcher):void
		{
			if (child is BubbleDispatcher)
			{
				(child as BubbleDispatcher).__my_parent__ = this;
			}
		}
 
		/**
		 * dispatch event, then bubble
		 * 
		 * @param	event
		 */
		public function bubble(event:Event):void
		{
			if (__my_parent__)
			{
				var neve:Event = event.clone();
				if (__my_parent__.myBubbleEventHandler(neve))
				{
					__my_parent__.bubble(neve);
				}
			}
		}
 
		/**
		 * it's better to be override in subclass
		 * 
		 * @param	event
		 * @return	true means continue bubble
		 */
		public function myBubbleEventHandler(event:Event):Boolean
		{
			//it's better to be override in subclass
			return true;
		}
	}
}

为了便于理解,我这里与AS3内置的EventDispatcher做些比较。

  • 把CBubbleDispatcher做父类(和EventDispatcher一样)。
  • 使用registerAsMyChild注册叶子对象(类似于addChild和addEventListener的组合,先把叶子对象作为当前对象的child,然后注册监听),这样的话,叶子抛出的事件对象就能被父亲对象处理了,或者再向上抛。
  • 使用bubble发出事件(相当于dispatchEvent)。
  • 子类重写myBubbleEventHandler来处理事件,返回true说明继续向上传递(类似于stopPropagation功能),如果不需要处理就不必重写。这样设计的好处是,不需要根据不同的Event type而写上很多很多的addEventListener。

补个小例子

class parent1Class extends CBubbleDispatcher
{
      public function parent1Class(){this.registerAsMyChild(_child);}
      private var _child:parent2Class = new parent2Class();
}
class parent2Class extends CBubbleDispatcher
{
      public function parent2Class(){this.registerAsMyChild(_child);}
      private var _child:childClass = new childClass();
}
class childClass extends CBubbleDispatcher
{
      public function try():void{this.bubble(new Event("UP"))};
}

RELATED POSTS

4 Comments

  1. Vniu says:

    呵呵,山寨的和原创就是不一样,有创意,不过还是有些不足

  2. admin says:

    to Vniu
    有哪些不足呢,指教下

  3. sban says:

    如果继承于CBubbleDispatcher,便不能继承其它;而自实现IBubbleDispathcer接口又嫌麻烦,能否设计出一个Manager,或者别的,可以方便的使用。

    此或为vniu所言不好之处。

  4. admin says:

    to sban

    其实我的初衷是让最基类继承CBubbleDispatcher,这样就不会干扰你的继承体系了

Leave a Reply