| [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专栏版块参加讨论
	      |