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 相关文章推荐
jQuery 自定义函数写法分享
Mar 30 Javascript
javascript利用控件对windows的操作实现原理与应用
Dec 23 Javascript
JS判断移动端访问设备并加载对应CSS样式
Jun 13 Javascript
详解js图片轮播效果实现原理
Dec 17 Javascript
JavaScript获取IP获取的是IPV6 如何校验
Jun 12 Javascript
jQuery实现点击某个div打开层,点击其他div关闭层实例分析(阻止冒泡)
Nov 18 Javascript
JS鼠标滚动分页效果示例
Jul 05 Javascript
ionic 3.0+ 项目搭建运行环境的教程
Aug 09 Javascript
详解JS构造函数中this和return
Sep 16 Javascript
JavaScript编写开发动态时钟
Jul 29 Javascript
解决ant Design中Select设置initialValue时的大坑
Oct 29 Javascript
echarts柱状图背景重叠组合而非并列的实现代码
Dec 10 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手册及PHP编程标准
2006/12/17 PHP
php跨域cookie共享使用方法
2014/02/20 PHP
php检查字符串中是否包含7位GSM字符的方法
2015/03/17 PHP
PHP面向对象学习之parent::关键字
2017/01/18 PHP
PHPCMS手机站伪静态设置详细教程
2017/02/06 PHP
PHP中使用jQuery+Ajax实现分页查询多功能操作(示例讲解)
2017/09/17 PHP
在laravel中实现ORM模型使用第二个数据库设置
2019/10/24 PHP
jquery实现的一个导航滚动效果具体代码
2013/05/27 Javascript
Jquery创建层显示标题和内容且随鼠标移动而移动
2014/01/26 Javascript
jQuery检查事件是否触发的方法
2015/06/26 Javascript
手机端转盘抽奖代码分享
2015/09/10 Javascript
Js自定义多选框效果的实例代码
2017/07/05 Javascript
JQuery获取元素尺寸、位置及页面滚动事件应用示例
2019/05/14 jQuery
ES6中的class是如何实现的(附Babel编译的ES5代码详解)
2019/05/17 Javascript
ES6 Object方法扩展的应用实例分析
2019/06/25 Javascript
JS前端知识点 运算符优先级,URL编码与解码,String,Math,arguments操作整理总结
2019/06/27 Javascript
在vue中created、mounted等方法使用小结
2020/07/21 Javascript
python获取各操作系统硬件信息的方法
2015/06/03 Python
解读Python编程中的命名空间与作用域
2015/10/16 Python
python实现画五角星和螺旋线的示例
2019/01/20 Python
python3.6中@property装饰器的使用方法示例
2019/08/17 Python
3行Python代码实现图像照片抠图和换底色的方法
2019/10/10 Python
Numpy 理解ndarray对象的示例代码
2020/04/03 Python
pycharm 2020 1.1的安装流程
2020/09/29 Python
HTML5 placeholder(空白提示)属性介绍
2013/08/07 HTML / CSS
Bath & Body Works阿联酋:在线购买沐浴和身体用品
2021/02/27 全球购物
物理研修随笔感言
2014/02/14 职场文书
2014新年元旦活动策划方案
2014/02/18 职场文书
运动会广播稿150字
2014/02/19 职场文书
经理助理岗位职责
2014/03/05 职场文书
2014国庆节幼儿园亲子活动方案
2014/09/16 职场文书
夫妻忠诚协议书范本
2014/11/17 职场文书
社区重阳节活动总结
2015/03/24 职场文书
2015圣诞节贺卡寄语
2015/03/24 职场文书
酒店总经理岗位职责
2015/04/01 职场文书
Idea连接MySQL数据库出现中文乱码的问题
2021/04/14 MySQL