qiqicode 发表于 2013-1-23 02:41:44

传统javascript事件模型实现观察者模式

来看一下这个东西mousemat.html:

<html> <head> <link rel='stylesheet' type='text/css' href='mousemat.css' /> <script type='text/javascript'>var cursor=null window.onload=function(){var mat=document.getElementById('mousemat');mat.onmousemove=mouseObserver;cursor=document.getElementById('cursor');} function mouseObserver(event){var e=event || window.event;writeStatus(e)drawThumbnail(e)} function writeStatus(e){window.status=e.clientX+","+e.clientY} function drawThumbnail(e){cursor.style.left=((e.clientX/5)-2)+"px";cursor.style.top=((e.clientY/5)-2)+"px";}</script> </head><body> <div class='mousemat' id='mousemat'></div> <div class='thumbnail' id='thumbnail'>   <div class='cursor' id='cursor'></div> </div> </body> </html>
并附上还有要用到的mousemat.css
.body{background-color: white;}.mousemat{background-color: #ffe0d0;border: solid maroon 2px;width: 500px;height: 500px;top: 24px;left: 24px;position: absolute;}.thumbnail{background-color: cyan;border: solid navy 1px;width: 100px;height: 100px;top: 24px;left: 528px;position: absolute;margin:0px;padding: 0px;}.cursor{background-color: navy;width:3px;height: 3px;position: relative;}

试试看,什么效果,然后再继续下面的吧


下面的会是同样的效果,只是代码复杂了,当然下面的代码是不完整的,只是核心部分。

首先简单介绍下需要模拟的东西,在W3C新的事件模型框架中,IE和Mozilla都实现了相应的版本,在基于Mozilla的浏览器和Safari中,使用addEventListener()来附加时间按回调,使用相应的removeEventListener()来删除,IE提供了类似的函数:attachEvent()和detachEvetn()。在传统的javascript时间模型中,我们无法为一个元素注册多个事件(任何事件),如何解决?
恩,是的,只有靠自己来实现观察者模式了。下面的代码来自《ajax in action》,加入了注释及相关说明。
注:对于观察者模式(Observer)是设计模式的一种,可以查看资料。

//命名空间,是的,只是一种形式var jsEvent = new Array();//构造函数//其中的el在实际中表示的是页面的dom元素(可以是一个button元素,一个div元素等等等),eventType表示的是事件对象(如onclick等等等)jsEvent.EventRouter = function(el,eventType){ //内部维护一个事件列表,这里的lsnrs很重要,里面存放当事件发生时我们需要的执行事件,是一个数组,所以允许我们把很多事件放进去 this.lsnrs = new Array(); this.el = el; el.eventRouter = this; //给el元素(记住el是一个页面元素)添加属性eventRouter,这个属性是当前的EventRouter对象 //注册回调函数,恩,已经知道了前面的,现在可以翻译下下面这一句了 //类似于:el.onclick = jsEvent.EventRouter.callback;(后面只是一个当onclick事件发生时需要执行的事件函数而已,具体的callback是什么将在后面的代码中涉及) el = jsEvent.EventRouter.callback;};//添加事件,使用了原型,注意添加在了哪里,是的,在上面那个构造函数里,什么用呢?答案是将需要在eventType(如onclick事件)发生时执行的动作事件放到lsnrs数组中,这里只是放进去,并没有执行。对于里面的执行的函数,下面也会说明,现在只是理清过程jsEvent.EventRouter.prototype.addListener = function(lsnr){ this.lsnrs.append(lsnr,true); } ;//移除事件,类似上面的增加事件jsEvent.EventRouter.prototype.removeListener = function(lsnr){ this.lsnrs.remove(lsnr); }; //通知所有事件,仍然看清楚这个属性函数加在了哪里,是的,还是在构造函数内,这个notify属性是真正执行、当事件发生时(如el元素被onclick)、需要执行的、被上面函数加在lsnrs数组中的、事件。这里用了奇怪的标点,只是为了不要产生误解jsEvent.EventRouter.prototype.notify = function(e){ var lsnrs = this.lsnrs; for(var i=0;i<lsnrs.length;i++){var lsnr = lsnrs;lsnr.call(this,e); }};//回调函数调用notify,看到了么,callback属性出现了,每当事件发生,都将调用notify函数,这样需要被执行的时间将被不断执行jsEvent.EventRouter.callback=function(event){ var e = event || window.event; var router = this.eventRouter; router.notify(e);};//下面的函数是用在addListener和removeListener中的,意思大家应该猜得出来了//直接在内建类array中增加原型,所有array类的对象都可以使用,其中obj是事件,当事件发生时需要执行的事件,obj对象需要有一个实现,而这里没有,nodup函数只是用来判断,当true时有效Array.prototype.append = function(obj,nodup){ if(nodup){   this=obj; //为什么位置在this.length?恩,这里不明说了,自己动脑筋吧 }};//o表示当lsnrs数组中的一个元素,代表一个事件Array.prototype.remove = function(o){   var i = this.indexOf(o);   if (i>-1){this.splice(i,1); //这个函数的作用是:The splice() method is used to remove and add new elements to an array。splice(数组起始位置,删除元素个数,添加的新元素【0】,……,添加的新元素【n】),是的大概是这样的,这里的表示现在该清楚了吧   }   return (i>-1);   } };好了,如何使用上面的对象呢:var mat=document.getElementById('mousemat');cursor=document.getElementById('cursor');var mouseRouter=new jsEvent.EventRouter(mat,"onmousemove");mouseRouter.addListener(writeStatus); //这里面的事件嘛就需要自己写了mouseRouter.addListener(drawThumbnail); //这里也一样

当然这里的只是些核心代码,如果需要运行,当然还要增加一些必要的东西。那么就到此为止吧,codd和他的朋友们头痛了~~~~~~
页: [1]
查看完整版本: 传统javascript事件模型实现观察者模式