创建侦听器函数是 ActionScript 3.0 事件模型与 DOM 事件模型不同的一个方面。在 DOM 事件模型中,事件侦听器和侦听器函数之间有一个明显的不同:即事件侦听器是实现 EventListener 接口的类的实例,而侦听器是该类的名为
handleEvent()
的方法。在 DOM 事件模型中,您注册的是包含侦听器函数的类实例,而不是实际的侦听器函数。
在 ActionScript 3.0 事件模型中,事件侦听器和侦听器函数之间没有区别。ActionScript 3.0 没有 EventListener 接口,侦听器函数可以在类外部定义,也可以定义为类的一部分。此外,无需将侦听器函数命名为
handleEvent()
— 可以将它们命名为任何有效的标识符。在 ActionScript 3.0 中,您注册的是实际侦听器函数的名称。
在类外部定义的侦听器函数
以下代码创建一个显示红色正方形的简单 SWF 文件。名为
clickHandler()
的侦听器函数(不是类的一部分)侦听红色正方形上的鼠标单击事件。
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, clickHandler);
}
}
function clickHandler(event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
当用户通过单击正方形与生成的 SWF 文件交互时,Flash Player 或 AIR 生成以下跟踪输出:
clickHandler detected an event of type: click
the this keyword refers to: [object global]
请注意,事件对象作为参数传递到
clickHandler()
。这就允许您的侦听器函数检查事件对象。在该示例中,使用事件对象的
type
属性来确定该事件是否为单击事件。
该示例还检查
this
关键字的值。在本例中,
this
表示全局对象,这是因为函数是在任何自定义类或对象外部定义的。
定义为类方法的侦听器函数
下面的示例与前面定义 ClickExample 类的示例相同,只是将
clickHandler()
函数定义为 ChildSprite 类的方法:
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, clickHandler);
}
private function clickHandler(event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
}
当用户通过单击红色正方形与生成的 SWF 文件交互时,Flash Player 或 AIR 生成以下跟踪输出:
clickHandler detected an event of type: click
the this keyword refers to: [object ChildSprite]
请注意,
this
关键字引用名为
child
的 ChildSprite 实例。这是与 ActionScript 2.0 相比行为方面的一个变化。如果您使用过 ActionScript 2.0 中的组件,您可能会记得,将类方法传递给
UIEventDispatcher.addEventListener()
时,方法的作用域被绑定到广播事件的组件,而不是在其中定义侦听器方法的类。也就是说,如果在 ActionScript 2.0 中使用该技术,
this
关键字将引用广播事件的组件,而不是 ChildSprite 实例。
这对于某些程序员来说是一个重要问题,因为这意味着他们无法访问包含侦听器方法的类的其他方法和属性。过去,ActionScript 2.0 程序员可以使用
mx.util.Delegate
类更改侦听器方法的作用域以解决该问题。不过,现在已不再需要这样做了,因为 ActionScript 3.0 在调用
addEventListener()
时会创建一个绑定方法。这样,
this
关键字引用名为
child
的 ChildSprite 实例,且程序员可以访问 ChildSprite 类的其他方法和属性。
不应使用的事件侦听器
还有第三种技术可用于创建一个通用对象,该对象具有指向动态分配的侦听器函数的属性,但不推荐使用该技术。在此讨论这种技术是因为它在 ActionScript 2.0 中经常使用,但在 ActionScript 3.0 中不应使用。建议不要使用此项技术,因为
this
关键字将引用全局对象,而不引用您的侦听器对象。
下面的示例与前面的 ClickExample 类示例相同,只是将侦听器函数定义为名为
myListenerObj
的通用对象的一部分:
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, myListenerObj.clickHandler);
}
}
var myListenerObj:Object = new Object();
myListenerObj.clickHandler = function (event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
跟踪的结果将类似如下:
clickHandler detected an event of type: click
the this keyword refers to: [object global]
您可能以为
this
引用
myListenerObj
,且跟踪输出应为
[object Object]
,但实际上它引用的是全局对象。将动态属性名称作为参数传递给
addEventListener()
时,Flash Player 或 AIR 无法创建绑定方法。这是因为作为
listener
参数传递的只不过是侦听器函数的内存地址,Flash Player 和 AIR 无法将该内存地址与
myListenerObj
实例
关联起来。