让Firefox支持event对象实现代码


Posted in Javascript onNovember 07, 2009

通常为了兼容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>
Javascript 相关文章推荐
JavaScript入门教程(12) js对象化编程
Jan 31 Javascript
JavaScript中检测变量是否存在遇到的一些问题
Nov 11 Javascript
深入理解javascript动态插入技术
Nov 12 Javascript
JavaScript获取路径设计源码
May 22 Javascript
Javascript变量的作用域和作用域链详解
Apr 02 Javascript
javascript设置和获取cookie的方法实例详解
Jan 05 Javascript
Angular页面间切换及传值的4种方法
Nov 04 Javascript
使用AngularJS2中的指令实现按钮的切换效果
Mar 27 Javascript
解决ie img标签内存泄漏的问题
Oct 13 Javascript
详解Vue2 添加对scss的支持
Jan 02 Javascript
node.js基于dgram数据报模块创建UDP服务器和客户端操作示例
Feb 12 Javascript
JavaScript代码实现微博批量取消关注功能
Feb 05 Javascript
extjs DataReader、JsonReader、XmlReader的构造方法
Nov 07 #Javascript
JavaScript 变量基础知识
Nov 07 #Javascript
表格 隔行换色升级版
Nov 07 #Javascript
csdn 论坛技术区平均给分功能
Nov 07 #Javascript
在js中单选框和复选框获取值的方式
Nov 06 #Javascript
模仿JQuery sortable效果 代码有错但值得看看
Nov 05 #Javascript
javaScript parseInt字符转化为数字函数使用小结
Nov 05 #Javascript
You might like
论建造顺序的重要性
2020/03/04 星际争霸
Yii2.0高级框架数据库增删改查的一些操作
2015/11/16 PHP
利用JQuery+EasyDrag 实现弹出可拖动的Div,同时向Div传值,然后返回Div选中的值
2009/10/24 Javascript
jquery keypress,keyup,onpropertychange键盘事件
2010/06/25 Javascript
Node.js的特点和应用场景介绍
2014/11/04 Javascript
jQuery插件Validate实现自定义表单验证
2016/01/18 Javascript
浅谈javascript的call()、apply()、bind()的用法
2016/02/21 Javascript
JavaScript代码性能优化总结篇
2016/05/15 Javascript
Bootstrap carousel轮转图的使用实例详解
2016/05/17 Javascript
微信小程序 location API接口详解及实例代码
2016/10/12 Javascript
JS实现延迟隐藏功能的方法(类似QQ头像鼠标放上展示信息)
2017/12/28 Javascript
bootstrap-table.js扩展分页工具栏(增加跳转到xx页)功能
2017/12/28 Javascript
详解angular分页插件tm.pagination二次触发问题解决方案
2018/07/20 Javascript
微信小程序第三方框架对比 之 wepy / mpvue / taro
2019/04/10 Javascript
Vue infinite update loop的问题解决
2019/04/23 Javascript
如何获取vue单文件自身源码路径
2019/05/06 Javascript
Vue中fragment.js使用方法小结
2020/02/17 Javascript
小程序实现可拖动的悬浮按钮
2020/09/07 Javascript
用Nodejs实现在终端中炒股的实现
2020/10/18 NodeJs
VUE-ElementUI 自定义Loading图操作
2020/11/11 Javascript
python生成日历实例解析
2014/08/21 Python
Python列表(list)常用操作方法小结
2015/02/02 Python
Python图像灰度变换及图像数组操作
2016/01/27 Python
Python中实现switch功能实例解析
2018/01/11 Python
Python2和Python3之间的str处理方式导致乱码的讲解
2019/01/03 Python
关于不懂Chromedriver如何配置环境变量问题解决方法
2019/06/12 Python
python如何将两张图片生成为全景图片
2020/03/05 Python
pandas apply多线程实现代码
2020/08/17 Python
娇韵诗加拿大官网:Clarins加拿大
2017/11/20 全球购物
Pureology官网:为染色头发打造最好的产品
2019/09/13 全球购物
办加油卡单位介绍信
2014/01/09 职场文书
婚前保证书范文
2015/02/28 职场文书
工作年限证明模板
2015/06/15 职场文书
golang DNS服务器的简单实现操作
2021/04/30 Golang
OpenCV实现常见的四种图像几何变换
2022/04/01 Python
CentOS7安装GlusterFS集群以及相关配置
2022/04/12 Servers