让Firefox支持event对象实现代码 |
本文标签:Firefox,event对象 通常为了兼容IE与FireFox,一般的事件处理方法为: 复制代码 代码如下: btn.onclick=handle_btn_click; function handle_btn_click(evt){ if(evt==null)evt=window.event;//IE //处理事件. } 对于简单的程序,这不算麻烦. 但对于一些复杂的程序,某写函数根本就不是直接与事件挂钩的.如果要把event传进该参数,那么所有的方法都要把event传来传去..这简直就是噩梦. 下面介绍一个解决这个麻烦事的方法,与原理. JScript中,函数的调用是有一个 func.caller 这个属性的. 例如 复制代码 代码如下: function A() { B(); } function B() { alert(B.caller); } 如果B被A调用,那么B.caller就是A 另外,函数有一个arguments属性. 这个属性可以遍历函数当前执行的参数: 复制代码 代码如下: function myalert() { var arr=[]; for(var i=0;i<myalert.arguments.length;i++) arr[i]=myalert.arguments[i]; alert(arr.join("-")); } myalert("hello","world",1,2,3) 就能显示 hello-world-1-2-3 (arguments的个数与调用方有关,而与函数的参数定义没有任何关系) 根据这两个属性,我们可以得到第一个函数的event对象: 复制代码 代码如下: btn.onclick=handle_click; function handle_click() { showcontent(); } function showcontent() { var evt=SearchEvent(); if(evt&&evt.shiftKey)//如果是基于事件的调用,并且shift被按下 window.open(global_helpurl); else location.href=global_helpurl; } function SearchEvent() { func=SearchEvent.caller; while(func!=null) { var arg0=func.arguments[0]; if(arg0) { if(arg0.constructor==Event) // 如果就是event 对象 return arg0; } func=func.caller; } return null; } 这个例子使用了SearchEvent来搜索event对象. 其中 Event 是 FireFox 的 event.constructor . 在该例子运行时, SearchEvent.caller就是showcontent,但是showcontent.arguments[0]是空.所以 func=func.caller 时,func变为handle_click . handle_click 被 FireFox 调用, 虽然没有定义参数,但是被调用时,第一个参数就是event,所以handle_click.arguments[0]就是event ! 针对上面的知识,我们可以结合 prototype.__defineGetter__ 来实现 window.event 在 FireFox 下的实现: 下面给出一个简单的代码.. 有兴趣的可以补充(本人已经有修改) 复制代码 代码如下: <script language="javascript"> function handle_click() { if(window.addEventListener) { FixPrototypeForGecko(); alert(window.event.srcElement) } } function FixPrototypeForGecko() { HTMLElement.prototype.__defineGetter__("runtimeStyle",element_prototype_get_runtimeStyle); window.constructor.prototype.__defineGetter__("event",window_prototype_get_event); Event.prototype.__defineGetter__("srcElement",event_prototype_get_srcElement); } function element_prototype_get_runtimeStyle() { //return style instead... return this.style; } function window_prototype_get_event() { return SearchEvent(); } function event_prototype_get_srcElement() { return this.target; } function SearchEvent() { //IE if(document.all) return window.event; func=SearchEvent.caller; while(func!=null) { var arg0=func.arguments[0]; if(arg0) { //if(arg0.constructor==Event) if(arg0.constructor==Event||arg0.constructor==MouseEvent || (typeof(arg0)=="object" && arg0.preventDefault && arg0.stopPropagation)) return arg0; } func=func.caller; } return null; } </script> <div id="mydiv" onclick="handle_click();">click here!!</div> javascript和JScript也是不相同的,前者是客户端的脚本,后者是服务端的脚本和VBScript一样被服务端所支持 当然我这里不是要说两者的区别,只是让自己了解到自己现在的水平(不是一般的差)... 如果就只给出了上面的代码,相信刚开始要搞兼容性的朋友一定很难看理解这些代码的用处 这里我就一一的解释下上面这些代码的用法吧 先看下__defineGetter__和__defineSetter__这两个方法的解释吧: 一.Getter是一种获取一个属性的值的方法,Setter是一种设置一个属性的值的方法 。可以为任何预定义的核心对象或用户自定义对象定getter和setter方法,从而为现有的对象添加新的属性 。 二.可以在什么时候对对象和事件添加新的属性? 1.在对象初始化时定义 2.在对象定义后通过Object的__defineGetter__、__defineSetter__方法来追加定义 详细的用法可以在请看这里对__defineGetter__、__defineSetter__的解释(地址:http://anbutu.javaeye.com/blog/post/194276) 所以我们看到了,在FixPrototypeForGecko()函数里分别给三个对象添加了属性,当然是在FF下对对象的添加: HTMLElement添加了"runtimeStyle"属性,属性值为element_prototype_get_runtimeStyle函数的返回的值 window添加了"event"属性,属性值为window_prototype_get_event返回的值 Event添加了"srcElement"属性,基属性值为event_prototype_get_srcElement函数所返回的值 这样我们就为这三个对象在FF下扩展了新的属性 所以我们在判断浏览器是否为FF后执行FixPrototypeForGecko()过程,这个时候在FF下这三个对象的就有了新的属性 于是当我们点击DIV标签后在弹出的窗口中我们看到了"[object HTMLDivElement]"字样,也说明我们已经成功的为window对象添加了event属性 复制代码 代码如下: if(window.addEventListener) { FixPrototypeForGecko(); alert(window.event.srcElement) } 大家可以看到element_prototype_get_runtimeStyle过程和event_prototype_get_srcElement过程所以返回的值都能很容易理解 那下面我们来看看window_prototype_get_event()过程是怎么样返回事件的 过程的返回值是SearchEvent()过程的结果,看下这个过程 复制代码 代码如下: function SearchEvent() { //IE if(document.all) return window.event; func=SearchEvent.caller; while(func!=null) { var arg0=func.arguments[0]; if(arg0) { //if(arg0.constructor==Event||arg0.constructor==MouseEvent) if(arg0.constructor==Event||arg0.constructor==MouseEvent || (typeof(arg0)=="object" && arg0.preventDefault && arg0.stopPropagation)) return arg0; } func=func.caller; } return null; } 要明白这个过程就得先明白两个方法:caller和arguments(在文章上面有相应的解释) 在这里再解释下constructor构造者这个属性,返回的是对象的相应对象的创建者 在while循环里alert(func)我们就可以看到func.caller的返回了,最后一次返回的就是我们的鼠标点击事件了 因为handle_click()过程是我们在点击div后执行的,所以最后的func.caller就是我们的点击事件了,这个时候的funcj就是 handle_click(),那么也就相当于是handle_click.caller,当然handle_click的调用者当然就是onclick 事件了,也就是[MouseEvent] 可以看到我在 if(arg0.constructor==Event||arg0.constructor==MouseEvent)增加了一个条件,是因为arg0.constructor现在的结果就是MouseEvent 看到这里相信大家也知道在FF下怎样编写event了 最后再说下"addEventListener"为对象注册事件方法 复制代码 代码如下: <script> function addObjectEvent(objId,eventName,eventFunc) { var targetObj = document.getElementById(objId); if(targetObj) { if(targetObj.attachEvent) { targetObj.attachEvent(eventName,eventFunc); } else if(targetObj.addEventListener) { eventName = eventName.toString().replace(/on(.*)/i,$1); targetObj.addEventListener(eventName,eventFunc,true); } } } function test1() { alert(test1); } function test2() { alert(test2); } </script> <div id="hi" onclick="MyTest();">on click</div> <script> addObjectEvent(hi,onclick,test1); addObjectEvent(hi,onclick,test2);//先执行test2(队列) </script> |