js中获取事件对象的方法小结


Posted in Javascript onMarch 13, 2011
var evt = window.event || arguments[0];

下面分三种添加事件的方式讨论,你也许会看到以前没有看到过的获取方式。
1,第一种添加事件的方式,直接在html的属性中写JS代码
<div onclick="alert(4);">Div1 Element</div>

大概这是上世纪90年代的写法,那时候直接把js代码写在网页中很普遍,也许那时候的js并不太重要,只是用来做做验证或一些花哨的效果而已。如何在这种添加事件方式下获取到事件对象?IE中很简单,因为event是作为全局对象的,所以直接使用event即可,如下
<div onclick="alert(window.event.type);">Div1 Element</div>

点击该Div后,IE中会弹出'click'字符的信息框。说明事件对象获取到了,如果在 Opera/Safari/Chrome 中也测试了,会发现效果和IE一样,说明 Opera/Safari/Chrome 中也支持IE方式( window.event )获取事件对象。
Firefox中会报错,提示:window.event is undefined,说明Firefox不支持IE方式获取事件对象而是以句柄的第一个参数传入的,文章开头意见提到了。
上面的用 window.event 来获取事件对象,其实window可以省略的,就像使用alert而不是window.alert一样。如
<div onclick="alert(event.type);">Div1 Element</div>

在 IE/Opera/Safari/Chrome 中测试,和刚刚不会有什么区别。在Firefox中再测,会有个惊喜,你会发现居然弹出的是"click"信息框,而不是"undefined"。
两次测试区别仅仅一个用window.event.type,一个用event.type。这个问题下面详细讨论。
下面用句柄第一个参数来获取事件对象,可以把onclick属性的值想象成一个匿名函数,onclick属性值的字符串实际上都是这个匿名函数内的js代码。
既然这样,我们就可以通过Function的一个属性argumengs获取到该匿名函数的第一个参数,而该参数就是事件对象。如
<div onclick="alert(arguments[0].type);">Div1 Element</div>

IE中会报错,提示:arguments.0.type为空或不是对象
Firefox/Opera/Safari/Chrome 中会弹出"click"内容的信息框,说明他们都支持事件对象作为句柄第一个参数传入。从侧面也说明了 Opera/Safari/Chrome 不仅支持W3C标准方式获取事件对象,同时也兼容了IE方式获取事件对象。
既然知道onclick对应的是一个匿名函数,我们不妨把该匿名函数打印出来看看,只需以下代码
<div onclick="alert(arguments.callee);">Div1 Element</div>

在各浏览器中点击该Div,结果如下:

IE6/7/8 :

function onclick(){ alert(arguments.callee);}

IE9 :

 function onclick(event){ alert(arguments.callee);}

Firefox / Safari :
function onclick(event) { alert(arguments.callee);}

Chrome :
function onclick(evt) { alert(arguments.callee);}

Opera :

 function anonymous(event) {alert(arguments.callee);}

观察这些函数发现:
IE6/7/8没有定义参数
IE9/Firefox/Safari/Opera 定义了参数event
Chrome定义了参数evt。
现在回到上面遗留的问题,如下

<div onclick="alert(window.event.type);">Div1 Element</div> 
<div onclick="alert(event.type);">Div1 Element</div>

这两个div的区别仅window.event.type和event.type。分别点击后,后者在Firefox中不弹出"undefined",而是"click",是因为Firefox中匿名函数定义了参数event,该参数刚好与IE的全局对象event同名,从而误以为Firefox也支持IE方式获取事件对象。

同样的道理,Chrome中定义的参数是evt,那么在Chrome中还可以通过以下方式获取事件对象,如下

<div onclick="alert(evt);">Div1 Element</div>

2,第二种添加事件的方式,定义一个函数,赋值给html元素的onXXX属性
<script type="text/javascript"> 
function clk(){} 
</script> 
<div onclick="clk()">Div2 Element</div>

先定义函数clk,然后赋值给onclick属性,这种方式也应该属于上世纪90年代的流行写法。比第一种方式好的是它把业务逻辑代码都封装在一个函数里了,使HTML代码与JS代码稍微有点儿分离,不至于第一种那么紧密耦合。
如何在这种方式(clk函数内)中获取事件对象?IE中使用全局对象event仍然没问题,如:
<script type="text/javascript"> 
function clk(){alert(window.event);} 
</script> 
<div onclick="clk()">Div2 Element</div>

点击Div后,除Firefox外,IE/Opera/Safari/Chrome都能正常获取事件对象。上面已经提到了 Opera/Safari/Chrome 兼容IE方式(window.event)获取事件对象,而唯独Firefox不支持。从而Firefox中只能通过参数传入了。试着这么写
<script type="text/javascript"> 
function clk(){alert(event);} 
</script> 
<div onclick="clk()">Div2 Element</div>

因为在Firefox中匿名函数是具有event参数的,而clk()是在匿名函数之内的,打印出匿名函数便知
<script type="text/javascript"> 
function clk(){alert(arguments.callee.caller);} 
</script> 
<div onclick="clk()">Div2 Element</div>

点击该Div,Firefox弹出信息框内容如下
function onclick(event) { 
clk(); 
}

回到clk中的alert(event),既然匿名函数的event传入了,那么在该闭包中clk是可以获取到event的,事实上点击后Firefox会报错:event is not defined。猜测该匿名函数的闭包和function clk(){alert(event);}不是同一个闭包环境。这种方式不行,则只能通过显示的参数传入了,如
<script type="text/javascript"> 
function clk(e){alert(e);} 
</script> 
<div onclick="clk(arguments[0])">Div2 Element</div>

点击Div,在Firefox中正确弹出了事件对象,支持参数传入的浏览器都可以,如Opera/Safari/Chrome。
把以上代码中的arguments[0]改成event,那么所有浏览器都支持。
把以上代码中的arguments[0]改成window.event,那么将只有Firefox不支持。
把以上代码中的arguments[0]改成evt,那么将只有Chrome支持。
思考下为什么?
3,第三种添加事件方式,使用element.onXXX方式
<div id="d3">Div3 Element</div> 
<script type="text/javascript"> 
var d3 = document.getElementById('d3'); 
d3.onclick = function(){ } 
</script>

这种方式也比较早期,但好处是可以将JS与HTML完全分离,但前提是需要给HTML元素提供一个额外的id属性(或其它能获取该元素对象的方式)。
这种方式添加事件IE6/7/8只支持window.event不支持参数传入,Firefox只支持参数传入不支持其它方式。IE9/Opera/Safari/Chrome 两种方式都支持。
4,第四种添加事件方式,使用addEventListener或IE专有的attachEvent
<div id="d4">Div4 Element</div> 
<script type="text/javascript"> 
var d4 = document.getElementById('d4'); 
function clk(){alert(4)} 
if(d4.addEventListener){ 
d4.addEventListener('click',clk,false); 
} 
if(d4.attachEvent){ 
d4.attachEvent('onclick',clk); 
} 
</script>

这是目前推荐的方式,较前两种方式功能更为强大,可以为元素添加多个句柄(或称响应函数),支持事件冒泡或捕获,前三种方式默认都是冒泡。当然IE6/7/8仍然没有遵循标准而使用了自己专有的attachEvent,且不支持事件捕获。IE9 中已经支持addEventListener了。
先用window.event测试,如
<script type="text/javascript"> 
var d4 = document.getElementById('d4'); 
function clk(){alert(window.event)} 
if(d4.addEventListener){ 
d4.addEventListener('click',clk,false); 
} 
if(d4.attachEvent){ 
d4.attachEvent('onclick',clk); 
} 
</script>

点击Div[id=d4],IE/Opera/Safari/Chrome都正确的弹出了事件对象信息框,Firefox弹出的是"undefined",预料之中,因为Firefox不支持window.event作为事件对象。
再换成句柄的第一个参数测试,如
<script type="text/javascript"> 
var d4 = document.getElementById('d4'); 
function clk(e){alert(e)} 
if(d4.addEventListener){ 
d4.addEventListener('click',clk,false); 
} 
if(d4.attachEvent){ 
d4.attachEvent('onclick',clk); 
} 
</script>

测试之前,猜测一下什么结果,可能有人会觉得IE中应该弹出undefined,其它浏览器都是事件对象。事实上所有浏览器弹出的信息框显示都是事件对象。
总结下:
1,IE6/7/8支持通过window.event获取对象,通过attachEvent方式添加事件时也支持事件对象作为句柄第一个参数传入
2,Firefox只支持事件对象作为句柄第一个参数传入
3,IE9/Opera/Safari/Chrome两种方式都支持
js中获取事件对象的方法小结
相关:
各浏览器事件对象差异性列表
Javascript 相关文章推荐
javascript判断iphone/android手机横竖屏模式的函数
Dec 20 Javascript
ajax不执行success回调而是执行了error回调
Dec 10 Javascript
用json方式实现在 js 中建立一个map
May 02 Javascript
javascript+HTML5的Canvas实现Lab单车动画效果
Aug 07 Javascript
基于jquery实现省市联动效果
Nov 23 Javascript
JavaScript 拖拽实例代码
Sep 21 Javascript
js实现悬浮窗效果(支持拖动)
Mar 09 Javascript
jQuery插件DataTables分页开发心得体会
Aug 22 jQuery
jq源码解析之绑在$,jQuery上面的方法(实例讲解)
Oct 13 jQuery
浅谈react受控组件与非受控组件(小结)
Feb 09 Javascript
webstrom Debug 调试vue项目的方法步骤
Jul 17 Javascript
vue-cli2 构建速度优化的实现方法
Jan 08 Javascript
js中关于new Object时传参的一些细节分析
Mar 13 #Javascript
重载toString实现JS HashMap分析
Mar 13 #Javascript
JavaScript获取页面上某个元素的代码
Mar 13 #Javascript
jQuery hover 延时器实现代码
Mar 12 #Javascript
js中if语句的几种优化代码写法
Mar 12 #Javascript
鼠标事件延时切换插件
Mar 12 #Javascript
autoIMG 基于jquery的图片自适应插件代码
Mar 12 #Javascript
You might like
php中json_encode UTF-8中文乱码的更好解决方法
2014/09/28 PHP
PHP 常用的header头部定义汇总
2015/06/19 PHP
php常用字符串String函数实例总结【转换,替换,计算,截取,加密】
2016/12/07 PHP
JQuery 小练习(实例代码)
2009/08/07 Javascript
JavaScript 学习笔记(十三)Dom创建表格
2010/01/21 Javascript
为你的网站增加亮点的9款jQuery插件推荐
2011/05/03 Javascript
jQuery源码分析-02正则表达式 RegExp 常用正则表达式
2011/11/14 Javascript
javascript查询字符串参数的方法
2015/01/28 Javascript
js去除浏览器默认底图的方法
2015/06/08 Javascript
js实现Select头像选择实时预览代码
2015/08/17 Javascript
jQuery定义插件的方法
2015/12/18 Javascript
jQuery使用正则表达式限制文本框只能输入数字
2016/06/18 Javascript
jQuery图片渐变特效的简单实现
2016/06/25 Javascript
Vue结合SignalR实现前后端实时消息同步
2017/09/19 Javascript
基于webpack 实用配置方法总结
2017/09/28 Javascript
C#实现将一个字符转换为整数
2017/12/12 Javascript
Webpack 4.x搭建react开发环境的方法步骤
2018/08/15 Javascript
vue自动路由-单页面项目(非build时构建)
2019/04/30 Javascript
使用Easyui实现查询条件的后端传递并自动刷新表格的两种方法
2019/09/09 Javascript
js实现拖动缓动效果
2020/01/13 Javascript
Linux下使用python自动修改本机网关代码分享
2015/05/21 Python
Python遍历目录并批量更换文件名和目录名的方法
2016/09/19 Python
老生常谈Python序列化和反序列化
2017/06/28 Python
对pandas进行数据预处理的实例讲解
2018/04/20 Python
Python工厂函数用法实例分析
2018/05/14 Python
python使用xlrd和xlwt读写Excel文件的实例代码
2018/09/05 Python
详解python函数的闭包问题(内部函数与外部函数详述)
2019/05/17 Python
关于ResNeXt网络的pytorch实现
2020/01/14 Python
使用PyTorch实现MNIST手写体识别代码
2020/01/18 Python
详解利用python识别图片中的条码(pyzbar)及条码图片矫正和增强
2020/11/17 Python
CSS3动画:5种预载动画效果实例
2017/04/05 HTML / CSS
中国领先的汽车保养服务平台:途虎养车
2019/10/18 全球购物
大学生实习自我鉴定
2013/12/11 职场文书
成龙霸王洗发水广告词
2014/03/14 职场文书
陈欧的广告词
2014/03/18 职场文书
数字化校园建设方案
2014/05/03 职场文书