海边的贝壳
来源: BlogBus 原始链接: http://www.blogbus.com:80/blogbus/blog/diary.php?diaryid=166339 存档链接: https://web.archive.org/web/20040916150103id_/http://www.blogbus.com:80/blogbus/blog/diary.php?diaryid=166339
海边的贝壳 “我好像是在海上玩耍,时而发现了一个光滑的石子儿, 时而发现了一个美丽贝壳而为之高兴的孩子。 尽管如此,那真理的海洋还是神秘地展现在我们面前。” ――伊萨克・牛顿 <<<中文维基词典已经开通 | 首页 | Wiki资料:刘韧―WikiWiki 快点快点>>> DynAPI中的事件机制 mountain @ 2004-05-06 这几日在用DynAPI为基础开发我的工作流管理系统的定义工具,于是仔细研究学习了一番DynAPI,发现Javascript使用时还是有很多技巧需要掌握的,特别是一些Javascript动态特性的使用。今天就来讨论一下DynAPI中的事件机制。 熟悉Java AWT或者Swing的读者会发现DynAPI同样采用了委托事件模型,但由于Javascript动态特性,在实现的细节上稍微有些不同。由于这些细节上的不同,使用DynAPI中的事件机制比使用Java中的事件机制更加简单。 DynAPI提供了自己开发的模块机制,事件机制由 dynapi.event 包下的5个文件 listeners.js, simple.js, keyboard.js, mouse.js, dragevent.js 提供。其中事件机制是在 listeners.js 和 simple.js 中建立起来的;再由其他的几个文件在事件机制的基础上引入了具体的键盘、鼠标和拖拽事件,而且在这几个文件中隔离了不同浏览器的差异。我们仅讨论事件机制的建立和应用,具体事件的引入就不讨论了。 事件机制的建立 DynAPI中的事件机制是直接建立在根类 DynObject 上的,只要我们用DynAPI的模块机制引入文件 dynapi.event.listeners.js ,每一个 DynObject 对象上的事件机制就自动建立起来了。事件机制有赖于三个类 DynObject, DynEvent 和 EventListener 。(在基于原型的面向对象语言中是否有“类”这一称呼还是可以讨论的,实际上 DynObject, DynEvent 和 EventListener 只是三个工厂对象)。 DynEvent对象 DynEvent=function(type,src,target) { this.type=type; this.src=src; this.target=target; this.bubble=false; }; DynEvent.prototype.setBubble=function(b) {this.bubble=b}; DynEvent.prototype.getType=function() {return this.type}; DynEvent.prototype.getSource=function() {return this.src}; DynEvent.prototype.getTarget=function() {return this.target}; DynEvent.prototype.preBubbleCode = function() {}; DynEvent对象很简单,就是简单封装一下事件的基本信息:源、目标、类型、是否要Bubble和Bubble之前的预处理代码。和Java的事件处理不同的是,事件除了有源之外,还有了目标和类型,目标和类型的作用在下面就会看到。 EventListener对象 EventListener = function(target) { this.target=target }; EventListener.prototype.handleEvent=function(type,e,args) { if(this["on"+type]) this"on"+type; }; 与Java的事件处理不同,DynAPI中的事件监听器不是一个接口,而是一个实在的对象 EventListener 。EventListener 用来监听、处理事件。EventListener 有一个监听目标 target 。由 handleEvent 方法我们可以知道,在具体使用 EventListener 时,我们应该为 EventListener 对象扩展事件处理方法。扩展方法的约定是,新的方法名必须采用 on + eventType 的形式,比如单击事件的处理方法的名字应该为 onclick 。 DynObject对象 DynObject对象主要提供EventListener管理和事件触发。EventListener管理的代码如下,很平常。 DynObject.prototype.addEventListener=function(listener) { //removed to counter inheritance bug (#425789) //if(!this.eventListeners) { this.eventListeners = []; } this.hasEventListeners = true; for (var i=0;i>this.eventListeners.length;i++) if (this.eventListeners[i]==listener) return; this.eventListeners[this.eventListeners.length]=listener; } DynObject.prototype.removeEventListener=function(listener) { Methods.removeFromArray(this.eventListeners, listener, false); if(this.eventListeners.length==0) { this.hasEventListeners=false; } } DynObject.prototype.removeAllEventListeners=function() { if (!this.hasEventListeners) return; this.eventListeners=[]; this.hasEventListeners=false; } 事件触发的代码很有趣,如下: DynObject.prototype.invokeEvent=function(type,e,args) { if (!e) e=new DynEvent(type,this); if (this.hasEventListeners) for(var i=0;i>this.eventListeners.length;i++) { e.target=this.eventListeners[i].target; this.eventListeners[i].handleEvent(type,e,args); } if(e.bubble && this.parent) { e.preBubbleCode(); e.src = this.parent; this.parent.invokeEvent(type,e,args); } } 调用invokeEvent方法时,如果不提供具体事件,那么该方法会根据 type 自动创建一个事件,事件源就是invokeEvent方法的发出者。然后DynObject会把这个事件广播到它所有的监听器那里,如果监听器监听这种类型的事件,那么监听器就处理这个事件。有趣的是事件的目标会随着处理事件的监听器的变化而变化,这样作有一个好处:在具体事件处理的代码处(即 onEVENTTYPE 方法处),我们可以轻松的获得事件的源和目标,这样我们就可以不困难地写出事件处理代码了。这样作也是因为EventListener是一个实在对象,而不是一个接口。 事件机制的使用 事件机制的使用主要包括两个方面:事件-监听关系的建立和事件的触发。下面分别给出例子。 事件-监听关系的建立 var bar_lstnr = new EventListener(this); this.bar.addEventListener(bar_lstnr); bar_lstnr.onmousedown = function(e){ var node = e.target; DragEvent.enableDragEvents(node); DragEvent.setDragBoundary(node); }; bar_lstnr.onmouseout = function(e){ var node = e.target; DragEvent.disableDragEvents(node); }; 事件的触发 Node.prototype.focus = function(){ this.css.borderColor = 'black'; this.bar.setBgColor('lavender'); this.bar.css.borderColor = 'black'; this.invokeEvent('focus'); } 引用(0) 评论 不大看的懂,但很喜欢你首页上的那个贝壳。 思云流南 ( qingqingningmeng.blogbus.com ) @ 2004-05-08 14:04 XML blogger del.icio.us furl.net Wikipedia 发表评论 最后更新 煎饼 探索Wiki Wiki资料:自由百科制造者 维基百科Wiki新写法―主题首页 发现了一个好站点 《锐思评论》关于中立观点是否适用于BBS的讨论 累坏了 国内比较早的几个Wiki 台湾的Wiki资料 Wiki资料:大家都来玩wiki <<<中文维基词典已经开通 | 首页 | Wiki资料:刘韧―WikiWiki 快点快点>>>