让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 相关文章推荐
asp 的 分词实现代码
May 24 Javascript
javascript prototype,executing,context,closure
Dec 24 Javascript
基于js与flash实现的网站flv视频播放插件代码
Oct 14 Javascript
不使用ajax实现无刷新提交表单
Dec 21 Javascript
详谈jQuery unbind 删除绑定事件 / 移除标签方法
Mar 02 Javascript
Angular实现较为复杂的表格过滤,删除功能示例
Dec 23 Javascript
解决vue cli使用typescript后打包巨慢的问题
Sep 30 Javascript
Jquery异步上传文件代码实例
Nov 13 jQuery
js实现简单的日历显示效果函数示例
Nov 25 Javascript
keep-alive不能缓存多层级路由菜单问题解决
Mar 10 Javascript
解决vuecli3中img src 的引入问题
Aug 04 Javascript
js canvas实现五子棋小游戏
Jan 22 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
PHP分页效率终结版(推荐)
2013/07/01 PHP
php读取csv实现csv文件下载功能
2013/12/18 PHP
UPUPW 更新 64 位 Apache 系列 PHP 7.0 正式版
2015/12/08 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
2020/02/23 PHP
JQuery Easyui Tree的oncheck事件实现代码
2010/05/28 Javascript
js对列表中第一个值处理与jsp页面对列表中第一个值处理的区别详解
2013/11/05 Javascript
jQuery 删除/替换DOM元素的几种方式
2014/05/20 Javascript
浅谈页面装载js及性能分析方法
2014/12/09 Javascript
node.js中的fs.rmdir方法使用说明
2014/12/16 Javascript
Ext JS框架程序中阻止键盘触发回退或者刷新页面的代码分享
2016/06/07 Javascript
Web打印解决方案之普通报表打印功能
2016/08/29 Javascript
Javascript json object 与string 相互转换的简单实现
2016/09/27 Javascript
微信小程序开发之视频播放器 Video 弹幕 弹幕颜色自定义实例
2016/12/08 Javascript
JS双击变input框批量修改内容
2016/12/12 Javascript
jQuery插件JWPlayer视频播放器用法实例分析
2017/01/11 Javascript
关于vue-resource报错450的解决方案
2017/07/24 Javascript
axios进阶实践之利用最优雅的方式写ajax请求
2017/12/20 Javascript
vue项目中添加单元测试的方法
2018/07/21 Javascript
vue2中,根据list的id进入对应的详情页并修改title方法
2018/08/24 Javascript
关于Vue项目跨平台运行问题的解决方法
2018/09/18 Javascript
vue设计一个倒计时秒杀的组件详解
2019/04/06 Javascript
js时间戳转yyyy-MM-dd HH-mm-ss工具类详解
2019/04/30 Javascript
Cordova(ionic)项目实现双击返回键退出应用
2019/09/17 Javascript
angular8和ngrx8结合使用的步骤介绍
2019/12/01 Javascript
基于vue和websocket的多人在线聊天室
2020/02/01 Javascript
详解python3实现的web端json通信协议
2016/12/29 Python
python简单线程和协程学习心得(分享)
2017/06/14 Python
Python Json序列化与反序列化的示例
2018/01/31 Python
python3安装pip3(install pip3 for python 3.x)
2018/04/03 Python
django1.11.1 models 数据库同步方法
2018/05/30 Python
Python获取好友地区分布及好友性别分布情况代码详解
2019/07/10 Python
css3 2D图片转动样式可以扩充到Js当中
2014/04/29 HTML / CSS
Vilebrequin欧洲官网:法国豪华泳装品牌(男士沙滩裤)
2018/04/14 全球购物
保险公司客户经理岗位职责
2015/04/09 职场文书
面试通知单大全
2015/04/20 职场文书
2016元旦文艺汇演主持词
2015/07/06 职场文书