在Firefox下编写event

在FireFox下编写事件处理函数是很麻烦的事.
因为FireFox并没有 window.event . 如果要得到 event 对象,就必须要声明时间处理函数的第一个参数为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)
                       return arg0;
               }
               func=func.caller;
           }
           return null;
}
</script>
<div here!!</div>
/*--------------------------------------------------------------------------------*/
下面是我对原文里例子的认识,有些啰嗦,还请见谅了...
由于是转载的文章,所以摸索了好久才得到了认识
原来JS里我有太多的不明白
javascript和JScript也是不相同的,前者是客户端的脚本,后者是服务端的脚本和VBScript一样被服务端所支持
当然我这里不是要说两者的区别,只是让自己了解到自己现在的水平(不是一般的差)...
如果就只给出了上面的代码,相信刚开始要搞兼容性的朋友一定很难看理解这些代码的用处
这里我就一一的解释下上面这些代码的用法吧
先看下__defineGetter__和__defineSetter__这两个方法的解释吧:
一.Getter是一种获取一个属性的值的方法,Setter是一种设置一个属性的值的方法。可以为任何预定义的核心对象或用户自定义对象定getter和setter方法,从而为现有的对象添加新的属性。
二.可以在什么时候对对象和事件添加新的属性?
1.在对象初始化时定义
2.在对象定义后通过Object的__defineGetter__、__defineSetter__方法来追加定义
详细的用法可以在请看这里对__defineGetter__、__defineSetter__的解释(地址:[url]http://anbutu.javaeye.com/blog/post/194276[/url])
所以我们看到了,在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)
                       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 click</div>
<script>
addObjectEvent('hi','onclick',test1);
addObjectEvent('hi','onclick',test2);//先执行test2(队列)
</script>
这里是原文地址:[url]http://blog.csdn.net/lqscoke/archive/2007/01/08/1477270.aspx[/url]
这是在网上找到的例子,可以看到例子中动态的给id为hi的div的onclick事件添加了执行的方法:test1和test2
但当点击div的时候我们发现先执行了test2然后才"执行test1,我例子中注释上写的是//先执行test2(队列)不知道是不是意味着多个方法的添加是以堆栈形式添加的,才有了最先加入的方法最后执行的顺序
算是理解得差不多了,但也还有不明确的地方,希望知情者能帮忙说明下,要是有说得不对的地方也望告知,好让我也能多了解JS,当不胜感谢~~
更多相关文章
  • 1.window.event对象 IE:有window.event对象 firefox:没有window.event对象.可以通过函数的参数传递event对象.例如:onmousedown=function(event) 解决办法:var e=window.event||event; 2.event ...
  • 在透明的flash在firefox下滚轮功能会失效,只有firefox有此问题,其他浏览器没有碰到过,这是因为firefox没有把鼠标的滚轮事件传给flash的原因.我们可以这样来解决: 1.在flash的宿主文件(HTML)下增加如下代码: <mce:script language=&quo ...
  • 两种python脚本运行方式一:以goagent为例编写   goagent.sh   后缀名:  .sh如我的goagent的proxy.py在/home/hadoop/programfiles/goagent/local目录下编写goagent.sh 内容如下:python /home/hado ...
  • Firefox下网页显示无样式,之前没有遇到过这种情况,网上查找,说是清空缓存,但是我清空了也没效果啊!最后,是通过下面的方式解决的:帮助->故障排除信息->重置Firefox...
  • 描述: XMLHttpRequest 在IE下正常,在Firefox下不起作用. 原因: XMLHttpRequest 对象的 onreadystatechange 不会在Firefox下执行, 解放方法: 使用 jQuery 实现 AJAX 去代替 XMLHttpRequest.
  • 最简单的可以使用nohupLinux下的Daemon简介1.Service就是指常驻内存大一些程序,且可以提供一些系统或是网络功能.提供service的那个程序就成为daemon.Daemon和service可以视为等同,不必刻意去区分.2.Daemon可以分为两类,一类是可独立启动的,成为stan ...
  • FontAwesome在Firefox下建立静态页面不显示的情况
    1.在相对路径时发现firefox的问题(但是在Chrome下没有问题),还需进一步确认. 最开始是直接把FontAwesome的less直接替换掉Bootstrap的glyphicons字体,编译后在firefox下一直是不显示,经过单独引用FontAwesome的css及font才发现如果换成第 ...
  • IE有3种方式都可以创建一个元素: 1 document.createElement("<input type=text>")2 document.createElement("<input>")3 document.createEle ...
一周排行
  • RelativeLayout相对布局各种常见的问题
      我是一个新手,刚开始接触android,我就今天学到的Relativelayout来和 ...
  • 12.1介质集
    12.1 介质集12.1.1 备份介质的类型 备份的介质(Media,也称媒体)有以下三种 ...
  • shell if 判断总结与实例if [ command ];then  符合该条件执行的语句 elif [ command ];then  符合该条件执行的语句 else  符合该条件执行的语句fi[-d DIR ...
  • wget http://download.redis.io/redis-stable.tar.gz tar xvzf redis-stable.tar.gz cd redis-stable make make ins ...
  • 5年前,谷歌骄傲地对全世界说它要"撤出"中国了,因为它觉得中国互联网的约束政策让它很不爽,所以它要用退出的方式坚守自己的原则.之后,一些好事者大肆渲染这起普通的商业行为,一些推波助澜者更是将其上升 ...
  • linux 诞生20年了,也成长了20年了.第一次看到linux,是在一份著名杂志上看到的关于linux的一些基础知识,确切说是关于linux的分区的,讲述如何分区才是合理的,我一下子就被这些吸引住了,从此以后踏入了 ...
  • emmet插件学习,练习中遇到一些问题
    emmet插件学习:帮助提高敲代码效率的插件  参考文献:Emmet(Zen coding ...
  • SMA、SMB、SMC封装的二极管
    以常见的贴片肖特基二极管SS14 SS24 SS34为例,三种管子区别主要在电流上,有三种 ...
  • openstack中的身份管理
    原文:http://blog.csdn.net/xxfigo/article/detail ...
  • 发现一个奇怪的现象,从puty 用相同的用户名和密码可以登录linux ,本地却不能登录久思不解,后百度发现是在安装oracle 10g时修改/etc/pam.d/login 里的时候session  require ...