LayaFlash极高程度还原了AS3的事件机制,AS3开发者可以使用原有的开发习惯和技巧与LayaFlash H5开发无缝衔接。LayaFlash事件不支持捕获阶段之外其他方面与AS3的用法一致,包括事件的冒泡。倘若已对AS3事件部分较为了解,可以跳过本节教程的内容。
教程示例项目源码下载:
1.事件机制原理和使用
事件机制可以让代码逻辑按照开发者事先预定的时机触发某个方法,与AS3的事件机制相同,LayaFlash的事件机制也包含以下几个要素:
1.1.注册和移除事件侦听器
1.2.事件类型
1.3.事件侦听器函数
1.4.事件对象
1.5.事件的派发
每个事件触发过程都有以上几个要素参与,只要对象继承了EventDispatch类就能侦听和派发事件。
以下代码示例给舞台添加一个鼠标事件(教程示例项目layaFlashEvent):
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class Main extends Sprite
{
public function Main():void
{
if (stage)
init();
else
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListene(Event.ADDED_TO_STAGE, init);
this.stage.addEventListener(MouseEvent.CLICK, stageClickHandler);
}
private function stageClickHandler(event:MouseEvent):void
{
this.stage.removeEventListener(MouseEvent.CLICK, stageClickHandler);
trace("stage is clicked.");
}
}
}1.1.注册和移除事件侦听器
LayaFlash IDE编译运行,点击舞台,可以看到调试工具的控制台输出了“stage is clicked.”:
代码示例中使用addEventListener方法给舞台添加了一个点击事件MouseEvent.CLICK:
this.stage.addEventListener(MouseEvent.CLICK, stageClickHandler);
stageClickHandler方法叫事件侦听器函数:
private function stageClickHandler(event:MouseEvent):void
{
trace(event.target + " is clicked.");
}这样只要有MouseEvent.CLICK 事件被派发,stageClickHandler就会被调用。实际上示例代码里的init方法也是一个事件侦听器函数,只不过它侦听的是Event.ADDED_TO_STAGE事件。有注册必然有移除,和addEventListener对应的是removeEventListener方法,调用它移除事件:
this.stage.removeEventListener(MouseEvent.CLICK,stageClickHandler);
须注意LayaFlash不能像AS3那样使用弱监听和事件优先级参数,以下代码的最后两个参数即使传递了在H5中不会生效:
this.stage.removeEventListener(MouseEvent.CLICK, stageClickHandler,true, 2);
定义事件侦听器函数的父对象如果和代码当前的对象不一致,需要使用bind方法先绑定作用域,然后再传入addEventListener方法。例如要添加事件侦听器函数的不是Main类的stageClickHandler方法,而是另一个自定义类StageChild中的方法就需要修改一下注册侦听器函数的代码(教程示例项目layaFlashEventBind)。
StageChild类的代码:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import iflash.method.bind;
import listenerDemo.StageChild;
public class Main extends Sprite
{
public function Main():void
{
if (stage)
init();
else
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var child:StageChild = new StageChild();
this.stage.addEventListener(MouseEvent.CLICK,
child.stageClickHandler);
}
}
} 修改Main里init的代码:
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var child:StageChild = new StageChild();
this.stage.addEventListener(MouseEvent.CLICK,
bind(child, child.stageClickHandler));
}bind方法让事件处理器函数的作用域和定义它的StageChild对象关联。在移除事件时也使用bind函数:
this.stage.removeEventListener(MouseEvent.CLICK, bind(child, child.stageClickHandler));
更多关于bind方法的内容请参看《LayaFlash新增方法》中的“函数作用域绑定:bind()”的内容。
1.2.事件类型
示例项目代码用到的MouseEvent.CLICK是事件类型,这个事件类型通常是系统派发的事件,开发者也可以调用dispatchEvent()方法派发这些事件,如何派发事件会在下面的内容涉及。
1.3.事件对象
每个事件侦听器函数在定义的时候必须带有一个方法参数:

event参数就是事件对象,此对象保存事件派发时传递到事件侦听器函数的信息,这些信息包含了事件侦听器函数要处理逻辑所用的数据。我们可以通过event.target属性和event.currentTarget属性获取到事件的派发者,并在事件处理器函数中访问事件派发者的属性。
1.4.事件的派发
如前所述,系统事件的派发通常是由系统负责,上述例子也是系统监听到用户点击舞台的操作才派发了一个MouseEvent.CLICK事件,才触发了stageClickHandler的逻辑,系统派发的代码在AS3是不可见的,但在LayaFlash里可以在EventDispatcher类看到代码实现,派发一个事件的代码为:
dispatchEvent(new MouseEvent(MouseEvent.CLICK));
派发事件就像发送江湖暗号,暗号一出,事先知道暗号所代表意思的一方就做出相应的行动。
2.自定义事件
我们使用的事件可以是系统现有的事件,也可以是自定义的事件,使用自定义类型的事件叫自定义事件。
三国演义里周瑜就曾在和刘备开会的时候想“掷杯为号”让刀斧手埋伏刘备,这“掷杯”就是事件,刀斧手事先被周瑜“注册”了这个事件,一旦周瑜真的“掷杯”,刀斧手就出来了。我们就以周瑜“掷杯为号”为例,说明一下如何使用自定义事件(示例项目layaFlashEventDropTheCup)。
代表周瑜的将军类General.as:
package myEvent
{
import flash.events.EventDispatcher;
public class General extends EventDispatcher
{
public function General()
{
super();
}
/**
* 掷杯为号
*
*/
public function dropCupAsSign(targetName:String):void
{
var event:KillEvent = new KillEven(KillEvent.DROP_THE_CUP_SIGN);
event.killTargetName = targetName;
this.dispatchEvent(event); //派发事件
}
}
}代表刀斧手的士兵类Solders.as:
package myEvent
{
import flash.events.EventDispatcher;
public class Soldiers extends EventDispatcher
{
public function Soldiers()
{
super();
}
/**
* 突然冲出来并干掉目标,这里是具体响应事件的侦听器函数
*
* @param event
*
*/
public function rushAndKillSomeOne(event:KillEvent):void
{
trace("kill the " + event.killTargetName + "!");
}
}
}自定义的事件类KillEvent.as:
package myEvent
{
import flash.events.Event;
public class KillEvent extends Event
{
public static const DROP_THE_CUP_SIGN:String = "dropTheCupSignEvent";
public var killTargetName:String;
public function KillEvent(type:String,
bubbles:Boolean = false, cancelable:Boolean = false)
{
super(type, bubbles, cancelable);
}
}
}修改Main.as中的代码:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import iflash.method.bind;
import myEvent.General;
import myEvent.KillEvent;
import myEvent.Soldiers;
public class Main extends Sprite
{
public function Main():void
{
if (stage)
init();
else
addEventListener(Event.ADDED_TO_STAGE, init);
}
private var _general:General; //周瑜
private var _solders:Soldiers; //刀斧手
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
_general = new General();
_solders = new Soldiers();
_general.addEventListener(KillEvent.DROP_THE_CUP_SIGN,
bind(_solders, _solders.rushAndKillSomeOne));
waitingSign(); //等待周瑜信号
}
private function waitingSign():void
{
this.stage.addEventListener(MouseEvent.CLICK,
stageClickHandler);
}
private function stageClickHandler(event:MouseEvent):void
{
this.stage.removeEventListener(MouseEvent.CLICK,
stageClickHandler);
_general.dropCupAsSign("刘备"); //触发事件
//移除自定义的事件
_general.removeEventListener(
KillEvent.DROP_THE_CUP_SIGN,
bind(_solders, _solders.rushAndKillSomeOne));
}
}
} 用LayaFlash编译代码后运行,点击舞台后可以看到LayaFlash IDE输出:

这里让用户扮演了一次周瑜,只要点击舞台就会让“周瑜”发出“掷杯”信号,让事先添加了自定义事件KillEvent.DROP_THE_CUP_SIGN的“刀斧手”做他们该做的事情。由于自定义的事件类定义了一个属性killTargetName,这是发送给事件侦听器函数的数据,从而影响执行逻辑时的结果。
事件不再使用时要及时移除,这跟AS3中使用事件时一样,大量没有使用的事件不及时移除会引发内存问题。被移除的事件除非被再次添加,否则不会生效。
