[6.建立强大的事件处理机制]
这一节讲建立强大的事件处理机制.学完这节,如果有接触过 AS3 的,马上会想到一句:这不就是 AS3 的事件处理机制吗? 的确.可以说跟 AS3 的事件处理机制一模一样.但还是有个作用域的问题.这节对想学习 AS3 的事件处理机制会有很大 帮助.如果你掌握这节中的内容,在 AS3 中就只有语法问题.也就会很快进入状态.毕竟是"水往低处流,人往高处走".对现 在用 AS2 的,学 AS3 是迟早的问题.不过 AS2 在新版本出来之前还是会很有用的(个人的看法).
作用域因为一样,前面也讲过,这里就不在啰嗦. 事件对象.这里已经创建一个 Event 类(或其子类)来代替.但功能一样.
这节讲的事件处理机制的形态(代码). 发送事件:
//继承. import AS2.events.Event; import AS2.events.CFEventDispatcher; class className extends CFEventDispatcher { ... this.dispatchEvent(new Event(Event.COMPLETE)); ... } 或
//不继承. import AS2.events.Event; import AS2.events.CFEventDispatcher; class className { public var addEventListener:Function; public var removeEventListener:Function; private var dispatchEvent:Function; public function className() { //此方法要在使用 dispatchEvent 方法前被执行.一般放于构造函数中. CFEventDispatcher.initialize(this); } ... this.dispatchEvent(new Event(Event.COMPLETE)); ... } 侦听事件:
//使用自定义函数. import AS2.events.Event; import className; ... var cn:className = new className(); //自定义函数. function completeHandler(evt:Event):Void { trace(this); //输出: _level0.cn } cn.addEventListener(Event.COMPLETE, completeHandler); ... 或
//使用事件侦听器对象. import AS2.events.Event; import className; ... var cn:className = new className(); //事件同名函数. function complete(evt:Event):Void { trace(this); //输出: this(指向侦听器对象) } cn.addEventListener(Event.COMPLETE, this); ... 移除侦听:
//使用自定义函数. ... cn.removeEventListener(Event.COMPLETE, completeHandler); ... 或
//使用事件侦听器对象. ... cn.removeEventListener(Event.COMPLETE, this); ... AS2.utils.CFDelegate; AS2.events.Event; AS2.events.CFEventDispatcher; 这些是什么?下面讲解:
[6.1.创建 CFDelegate 类(修改 Delegate 类)] CFDelegate 类是 Delegate 类的修改版本.简化了代码(一般不用的功能).提高了执行效率.
此类文档详细: Classes/AS2/utils/CFDelegate.as
主类: 打开 CFDelegate.as 文档.输入下面的代码:
class AS2.utils.CFDelegate { public static function create(scope:Object, method:Function):Function { var f:Function = function () { method.apply(scope, arguments); }; return f; } } 保存文档.
[6.2.创建 CFEventDispatcher 类(修改 EventDispatcher 类)] CFEventDispatcher 类是 EventDispatcher 类的修改版本.简化了代码(一般不用的功能).提高了执行效率.
此类文档详细: Classes/AS2/events/CFEventDispatcher.as
主类: 打开 CFEventDispatcher.as 文档.输入下面的代码:
*/ //---------------------------------------- class AS2.events.CFEventDispatcher { //---------------------------------------- //构造函数 public function CFEventDispatcher(){} //---------------------------------------- //当不继承此类时,此属性才有效. private static var _ed:CFEventDispatcher; //---------------------------------------- private static function _removeEventListener(queue:Object, handler):Void { /* 这里主要用于删除事件数组中的事件处理器. */ if (queue != undefined) { var l:Number = queue.length; while(l--){ if(queue[l] == handler){ queue.splice(l, 1); return; } } } } //当不继承此类时.此方法有效. public static function initialize(o:Object):Void { /* 如果没有继承此类,而是使用 initialize 此方法时, _ed 等于 undefined.然后创建此类的实例. 最后将事件通知和侦听器管理功能添加到 initialize 方法中的对象 o. 前面所讲的不继承此类时需添加的三个方法,其实是四个.还有 dispatchQueue 方法.但此方法在 调用 dispatchEvent 方法时就会自动调用.可能有人会问,为什么没有定义就能调用?因为在函数 中可以操作对象.从而对对象动态添加方法和属性.这里就是用了在函数中操作对象. */ if (_ed == undefined) { _ed = new CFEventDispatcher(); } o.addEventListener = _ed.addEventListener; o.removeEventListener = _ed.removeEventListener; o.dispatchEvent = _ed.dispatchEvent; o.dispatchQueue = _ed.dispatchQueue; } //---------------------------------------- private function dispatchQueue(queueObj:Object, eventObj:Object):Void { /* 这里主要用于判断事件处理器是对象还是函数. */ if (queueObj[eventObj.type] != undefined) { for (var i:String in queueObj[eventObj.type]) { var o = queueObj[eventObj.type][i]; if (typeof (o) == "object" || typeof (o) == "movieclip") { //调用对象中的handleEvent函数. //if (o.handleEvent != undefined) { //o.handleEvent(eventObj); //} //调用对象中的事件同名函数. //if (o[eventObj.type] != undefined) { o[eventObj.type](eventObj); //} } else { //调用自定义函数. o.apply(queueObj, [eventObj]); } } } } public function dispatchEvent(eventObj:Object):Void { //将事件源始终指向this(应用此类的对象). eventObj.target = this; //此句对动态类,或在类中定义"事件名Handler" 这样的函数时才有效.在这里我注释了这句.你如果你想用,可以启用它. /* 用法: 对象.事件名Handler = function(evt:Object){}; */ //this[eventObj.type + "Handler"](eventObj); this.dispatchQueue(this, eventObj); } public function addEventListener(event:String, handler):Void { //这里可以这样理解: /* 使用 addEventListener("click", 事件处理器); 添加事件. 这时, this["click"] 就等于 undefined. (this["click"] == undefined) = true 然后将创建一个新数组来存储事件处理器. this["click"] = []; 然后执行 CFEventDispatcher._removeEventListener(this["click"], 事件处理器); 来检测此事件是否有相同的事件处理器.如果是就删除它. 举个例:当你在一个网站注册用户名时.网站的注册程序会从数据库中检测是否有与你相同的用户名. 如果有将会提示你重新输入用户名(在这里就是直接删除了).如果没有就会注册成功(这里就在后面 执行 push).但是网站的注册程序不会从数据库中检测是否有与你相同的密码. 就是说一个事件,可添加多个不同的事件处理器,但不能添加相同的事件处理器. 当添加新的事件时,也是一样的 最后使用 this["click"].push(事件处理器); 将事件处理器添加到事件数组. */ if (this[event] == undefined) { this[event] = new Array(); } //ASSetPropFlags 是隐藏的方法.用它和不用它貌似没有区别.大家可以研究下. //_global.ASSetPropFlags(this, event, 1); CFEventDispatcher._removeEventListener(this[event], handler); this[event].push(handler); } public function removeEventListener(event:String, handler):Void { //这里我就不啰嗦了. CFEventDispatcher._removeEventListener(this[event], handler); } //---------------------------------------- } 保存文档.
[6.3.创建 Event 类(事件基类,继承 Object 类)] 你可以把它看作事件对象.因应它的工作就是生成事件对象.
此类文档详细: Classes/AS2/events/Event.as
主类: 打开 Event.as 文档.输入下面的代码:
class AS2.events.Event extends Object { //---------------------------------------- //事件的常数名. public static var COMPLETE:String = "complete"; public static var CANCEL:String = "cancel"; public static var CHANGE:String = "change"; public static var CLOSE:String = "close"; public static var CONNECT:String = "connect"; public static var FULLSCREEN:String = "fullScreen"; public static var OPEN:String = "open"; public static var REMOVED:String = "removed"; public static var RESIZE:String = "resize"; public static var SCROLL:String = "scroll"; public static var SELECT:String = "select"; //---------------------------------------- public var type:String; public var target:Object; //---------------------------------------- private var className:String = "Event"; //---------------------------------------- //构造函数. public function Event(type:String) { this.type = type; } //---------------------------------------- public function toString():String { var str:String = ""; for (var i:String in this) { if (this[i] != undefined) { str += i + "=" + this[i] + " "; } } return "[" + this.className + " " + str.slice(0,str.length - 1) + "]"; } //---------------------------------------- } 保存文档.
此类包含下面内容: 1.事件的常数名.如:
public static var COMPLETE:String = "complete"; ... 2.基本的属性.如:
public var type:String; ... 3.className 属性.如:
private var className:String = "Event"; 4.构造函数.如:
public function Event(type:String) { this.type = type; } 5.toString() 方法.如:
public function toString():String { var str:String = ""; for (var i:String in this) { if (this[i] != undefined) { str += i + "=" + this[i] + " "; } } return "[" + this.className + " " + str.slice(0,str.length - 1) + "]"; }
如果你嫌此方法阻碍你的执行效率.可以改成如下(标准):
public function toString():String { return "[object " + this.className + "]"; } 这里讲下 toString() 方法.在类中定义此方法.在输出此类实例名实调用此方法.如:
class className { ... private var className:String = "className"; public function toString():String { return "[object " + this.className + "]"; } ... }
import className; var cn:className = new className(); trace(cn);// 调用 toString() 方法.输出: [object className] 当然你也可以改成 AS3 中 Event 类一样的方法.但没有必要,很少会用到. 如果要向 Event 类传递参数和定义新的事件名,请看下面.
[6.4.创建 IOErrorEvent 类(错误事件类,继承 Event 类)] 此类文档详细: Classes/AS2/events/IOErrorEvent.as
主类: 打开 IOErrorEvent.as 文档,输入下面的代码:
import AS2.events.Event; //---------------------------------------- class AS2.events.IOErrorEvent extends Event { //---------------------------------------- //事件的常数名. public static var IO_ERROR:String = "IOError"; //---------------------------------------- //属性参数. public var text:String; //---------------------------------------- //className 属性 private var className:String = "IOErrorEvent"; //---------------------------------------- //在构造函数中添加参数. public function IOErrorEvent(type:String, text:String) { super(type); this.text = text; } //---------------------------------------- } 保存文档.
[6.5.创建 HTTPStatusEvent 类(http状态事件类,继承 Event 类)] 此类文档详细: Classes/AS2/events/HTTPStatusEvent.as
主类: 打开 HTTPStatusEvent.as 文档.输入下面的代码:
import AS2.events.Event; //---------------------------------------- class AS2.events.HTTPStatusEvent extends Event { //---------------------------------------- //事件的常数名. public static var HTTP_STATUS:String = "httpStatus"; //---------------------------------------- //属性参数. public var status:Number; //---------------------------------------- //className 属性 private var className:String = "HTTPStatusEvent"; //---------------------------------------- //在构造函数中添加参数. public function HTTPStatusEvent(type:String, status:Number) { super(type); this.status = status; } //---------------------------------------- } 保存文档.
[6.6.示例: EventClass 类(简单的示例)] 此示例文档详细: Example/AS2/events/Event/EventClass.as Example/AS2/events/Event/EventExample.as Example/AS2/events/Event/EventExample.xml Example/AS2/events/Event/EventExample.fla
主类: 打开 EventClass.as 文档.输入下面的代码:
import AS2.utils.CFDelegate; import AS2.events.Event; import AS2.events.IOErrorEvent; import AS2.events.HTTPStatusEvent; import AS2.events.CFEventDispatcher; //---------------------------------------- class EventClass extends CFEventDispatcher { //---------------------------------------- public var tXML:XML; //---------------------------------------- public function EventClass(url:String) { this.tXML = new XML(); this.tXML.onLoad = CFDelegate.create(this, this.XMLonLoad); this.tXML.onHTTPStatus = CFDelegate.create(this, this.XMLHTTPStatus); this.tXML.load(url); } public function toString():String { return "[EventClass]"; } //---------------------------------------- private function XMLonLoad(success:Boolean):Void { if (success) { this.dispatchEvent(new Event(Event.COMPLETE)); } else { this.dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR, "加载错误!请检查 XML 文档地址和网络连接")); } } private function XMLHTTPStatus(httpStatus:Number):Void { this.dispatchEvent(new HTTPStatusEvent(HTTPStatusEvent.HTTP_STATUS, httpStatus)); } //---------------------------------------- } 保存文档.
示例类: 打开 EventExample.as 文档.输入下面的代码(手指应该很痛吧.呵.我也一样.(可能是无谓的话)):
import EventClass; import AS2.events.Event; import AS2.events.IOErrorEvent; import AS2.events.HTTPStatusEvent; //---------------------------------------- class EventExample { public function EventExample() { var ee:EventClass = new EventClass("http://localhost/Examples/AS2/events/Event/EventExample.xml"); ee.addEventListener(Event.COMPLETE, this.completeHandler); ee.addEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler); ee.addEventListener(HTTPStatusEvent.HTTP_STATUS, this.httpStatusHandler); } private function completeHandler(evt:Event):Void { trace(evt); } private function ioErrorHandler(evt:IOErrorEvent):Void { trace(evt); } private function httpStatusHandler(evt:HTTPStatusEvent):Void { trace(evt); } } 保存文档. 这里注意 XML 文档地址不是本地地址,是用服务器地址的(测试 http 状态用):
var ee:EventClass = new EventClass("http://localhost/Examples/AS2/events/Event/EventExample.xml"); 要加载的 XML 文档: 打开 EventExample.xml 文档,随便输入一些内容便可.测试用.
示例 fla 文档: 打开 EventExample.fla 文档.将"图层 1"重命名为 Actions.并在第一帧中输入下面的代码:
new EventExample(); 保存文档. 测试 Flash 文档.在 XML 文档成功加载后会在输出面板中显示以下内容:
[HTTPStatusEvent target=[EventClass] status=200 type=httpStatus] [Event target=[EventClass] type=complete] 当将 XML 地址改成错误时,在输出面板中将显示以下内容:
Error opening URL "http://localhost/Example/AS2/events/Event/EventExamples.xml" [HTTPStatusEvent target=[EventClass] status=404 type=httpStatus] [IOErrorEvent target=[EventClass] text=加载错误!请检查 XML 文档地址和网络连接 type=IOError] 下面再看一个示例: [6.7.示例: Timer 类(定时器,功能跟 AS3 中的 Timer 类一样)] 此示例文档详细: Classes/AS2/utils/Timer.as Classes/AS2/utils/TimerEvent.as Example/AS2/utils/Timer/TimerExample.as Example/AS2/utils/Timer/TimerExample.fla
主类: 打开 Timer.as 文档,输入下面的代码:
import AS2.utils.TimerEvent; import AS2.utils.CFDelegate; import AS2.events.CFEventDispatcher; //---------------------------------------- class AS2.utils.Timer extends CFEventDispatcher { //---------------------------------------- private var _timerID:Number; private var _delay:Number; private var _repeatCount:Number; private var _currentCount:Number = 0; private var _running:Boolean; //---------------------------------------- /* @parameter delay: 延迟,单位毫秒. @parameter repeatCount: 重复次数.默认为Infinity(正无穷大); */ public function Timer(delay:Number, repeatCount:Number) { if (isNaN(delay)) { return; } if (isNaN(repeatCount)) { repeatCount = Infinity; } this._delay = delay; this._repeatCount = repeatCount; } //---------------------------------------- public function reset():Void { this._currentCount = 0; this.stop(); } public function start():Void { this._timerID = setInterval(CFDelegate.create(this, this.startTimer), this._delay); this._running = true; } public function stop():Void { clearInterval(this._timerID); this._running = false; } public function toString():String { return "[Timer]"; } //---------------------------------------- private function startTimer():Void { this._currentCount++; this.dispatchEvent(new TimerEvent(TimerEvent.TIMER, this._currentCount)); if (this._currentCount == this._repeatCount) { this.reset(); this.dispatchEvent(new TimerEvent(TimerEvent.TIMER_COMPLETE)); } } //---------------------------------------- public function get delay():Number { return this._delay; } public function set delay(d:Number):Void { this._delay = d; } public function get repeatCount():Number { return this._repeatCount; } public function set repeatCount(r:Number):Void { this._repeatCount = r; } public function get currentCount():Number { return this._currentCount; } public function get running():Boolean { return this._running; } //---------------------------------------- } 保存文档.
Timer 事件类: 打开 TimerEvent.as 文档,输入下面的代码:
import AS2.events.Event; //---------------------------------------- class AS2.utils.TimerEvent extends Event { //---------------------------------------- public static var TIMER:String = "timer"; public static var TIMER_COMPLETE:String = "timerComplete"; //---------------------------------------- public var currentCount:Number; //---------------------------------------- private var className:String = "TimerEvent"; //---------------------------------------- public function TimerEvent(type:String, currentCount:Number) { super(type); this.currentCount = currentCount; } //---------------------------------------- } 保存文档.
示例类: 打开 TimerExample.as 文档,输入下面的代码:
import AS2.utils.Timer; import AS2.utils.TimerEvent; //---------------------------------------- class TimerExample { //---------------------------------------- public function TimerExample() { var te:Timer = new Timer(1000, 5); te.addEventListener(TimerEvent.TIMER, this.timerHandler); te.addEventListener(TimerEvent.TIMER_COMPLETE, this.timerCompleteHandler); te.start(); } private function timerHandler(evt:TimerEvent):Void { trace("timer: " + evt); } private function timerCompleteHandler(evt:TimerEvent):Void { trace("timerComplete: " + evt); } //---------------------------------------- } 保存文档.
示例 fla 文档: 打开 TimerExample.fla 文档,将"图层 1"重命名为 Actions.并在第一帧中输入下面的代码:
new TimerExample(); 保存文档. 测试 Flash 文档.在输出面板可以看到下面的内容:
timer: [TimerEvent target=[Timer] currentCount=1 type=timer] timer: [TimerEvent target=[Timer] currentCount=2 type=timer] timer: [TimerEvent target=[Timer] currentCount=3 type=timer] timer: [TimerEvent target=[Timer] currentCount=4 type=timer] timer: [TimerEvent target=[Timer] currentCount=5 type=timer] timerComplete: [TimerEvent target=[Timer] type=timerComplete]
经典论坛讨论: http://bbs.blueidea.com/thread-2768209-1-1.html
出处:蓝色理想
责任编辑:蓝色月光
上一页 [AS2]事件处理机制 -- 使用addListener方法 二 下一页 [AS2]事件处理机制 -- 小结
◎进入论坛Flash专栏版块参加讨论
|