DOM 中的事件处理介绍


Posted in Javascript onJanuary 18, 2012

该接口提供了 'addEventListener' 和 'removeEventListener' 方法,用来绑定或解绑一个 EventListeners 接口到一个 EventTarget。

DOM 2 Events 中定义了 Event 接口,用来提供事件的上下文信息,它提供了若干标准属性和方法。 实现 Event 接口的对象一般作为第一个参数传入事件处理函数,以用来提供当前事件相关的一些信息。

事件注册
根据 DOM 2 Events 中描述,节点使用 'addEventListener' 和 'removeEventListener' 方法绑定和解绑事件监听器,但 IE6 IE7 IE8 不支持这两个方法, 而使用 'attachEvent' 和 'detachEvent' 方法作为替代方案,Opera 两类方法都支持。Chrome Safari Firefox 只支持标准方法。

为了解决浏览器兼容问题,可以自定义函数来解决。例如:

var EventUtil = { 
addHandler: function (element, type, handler) { 
if (element.addEventListener) { 
element.addEventListener(type, handler, false); 
} else if (element.attachEvent) { 
element.attachEvent("on" + type, handler); 
} else { 
element["on" + type] = handler; 
} 
}, 
removeHandler: function (element, type, handler) { 
if (element.removeEventListener) { 
element.removeEventListener(type, handler, false); 
} else if (element.detachEvent) { 
element.detachEvent("on" + type, handler); 
} else { 
element["on" + type] = null; 
} 
} 
};

关于 'addEventListener' 和 'attachEvent' 有几点需要注意:

IE 不支持在捕获阶段触发事件监听器,'attachEvent' 方法没有提供参数说明是否响应在捕获阶段触发的事件;
'addEventListener' 和 'attachEvent' 都可以注册多个事件监听器;
在 Firefox Chrome Safari Opera 中给同一事件注册同一个事件监听器多次,重复注册的会被丢弃;而在 IE 中重复注册的事件监听器会被重复执行多次;
当给同一元素注册了多个事件监听器的时候,IE6 IE7 的事件监听器执行顺序是随机的,IE8 是倒序的,Firefox Chrome Safari Opera 是顺序的;
当元素注册的事件监听器中有非法的事件监听器时(非函数),在 IE Firefox 中会抛出异常,而在 Chrome Safari Opera 中则会忽略非法的事件监听器,继续执行其他的事件监听器。
事件对象
在ie中,事件对象是作为一个全局变量来保存和维护的。 所有的浏览器事件,不管是用户触发的,还是其他事件, 都会更新window.event 对象。 所以在代码中,只要轻松调用 window.event 就可以轻松获取 事件对象, 再 event.srcElement 就可以取得触发事件的元素进行进一步处理。

对于标准的 DOM 处理来说, 事件对象却不是全局对象,一般情况下,是现场发生,现场使用,把事件对象自动传递给对应的事件处理函数。 在代码中,函数的第一个参数就是事件对象了。

为了解决兼容性问题,通常在代码中如下处理:

function handler(e){ 
e = e || window.event; 
}

需要注意的是,使用 <button id="btn" onclick="foo()">按钮1</button> 进行事件注册,标准方式下却不能在事件处理方法中取得事件对象。

原因是 onclick="foo()" 就是直接执行了, foo() 函数,没有任何参数传递给 foo 函数。

有两个办法解决这个问题。

第一,将注册的方法修改为 <button id="btn" onclick="foo(event)">按钮</button>,注意,这里的 event 不是形参,而是实参,必须名为 event。这样 foo 函数就可以得到事件参数了。

第二,不修改注册的代码,在事件处理方法上进行处理。关键在于此时实际上存在事件对象,只不过没有传递给 foo 函数罢了,我们可以找到调用 foo 函数的那个函数,当然这是一个系统函数,没有关系,通过 foo.caller 可以取得当前调用 foo 函数的函数,这个函数的第一个参数就是事件对象,所以,我们可以这样取得这个事件对象了。foo.caller.arguments[0]。

注意:

只有在使用 attachEvent 方法注册事件监听器的时候,IE 才支持使用事件监听器传入的第一个参数作为事件对象的方式;
Chrome Safari Opera 两种获取事件对象的方式都支持;
Firefox 只支持获取事件对象的标准方式。
事件对象的属性
IE 对事件对象的标准属性和方法支持有限,针对大部分属性和方法,IE 都提供了一套替代非标准的替代方案; 而 Firefox Chrome Safari Opera 除了全面支持事件对象的标准属性和方法外,还在不同程度上支持了 IE 提供的非标准替代方案。

使用特性判断使用与标准对应的非标准方法及属性

target

srcElement

preventDefault()

 returnValue

stopPropagation()

cancelBubble

relatedTarget

fromElement toElement

例如:

getEvent: function (event) { 
return event ? event : window.event; 
}, 
getTarget: function (event) { 
return event.target || event.srcElement; 
}, 
preventDefault: function (event) { 
if (event.preventDefault) { 
event.preventDefault(); 
} else { 
event.returnValue = false; 
} 
}, 
stopPropagation: function (event) { 
if (event.stopPropagation) { 
event.stopPropagation(); 
} else { 
event.cancelBubble = true; 
} 
}

参考资料:

SD9011: 事件模型在各浏览器中存在差异

Javascript 相关文章推荐
JavaScript方法和技巧大全
Dec 27 Javascript
javascript 三种编解码方式
Feb 01 Javascript
常见效果实现之返回顶部(结合淡入、淡出、减速滚动)
Jan 04 Javascript
jQuery:delegate中select()不起作用的解决方法(实例讲解)
Jan 26 Javascript
使用jQuery实现WordPress中的Ctrl+Enter和@评论回复
May 21 Javascript
JQueryEasyUI之DataGrid数据显示
Nov 23 Javascript
AngularJS控制器controller给模型数据赋初始值的方法
Jan 04 Javascript
node.js中grunt和gulp的区别详解
Jul 17 Javascript
React+react-dropzone+node.js实现图片上传的示例代码
Aug 23 Javascript
AngularJs 禁止模板缓存的方法
Nov 28 Javascript
浅谈Vue.js中ref ($refs)用法举例总结
Dec 19 Javascript
Vue实现背景更换颜色操作
Jul 17 Javascript
深入理解JavaScript系列(13) This? Yes,this!
Jan 18 #Javascript
JavaScript中常用的运算符小结
Jan 18 #Javascript
jQuery LigerUI 使用教程表格篇(1)
Jan 18 #Javascript
jQuery LigerUI 使用教程入门篇
Jan 18 #Javascript
c#和Javascript操作同一json对象的实现代码
Jan 17 #Javascript
深入理解JavaScript系列(12) 变量对象(Variable Object)
Jan 16 #Javascript
Prototype源码浅析 Enumerable部分之each方法
Jan 16 #Javascript
You might like
PHP5.3的垃圾回收机制(动态存储分配方案)深入理解
2012/12/10 PHP
php堆排序(heapsort)练习
2013/11/13 PHP
JavaScript 异步调用框架 (Part 2 - 用例设计)
2009/08/03 Javascript
javascript 当前日期转化为中文的实现代码
2010/05/13 Javascript
JS 使用for循环遍历子节点查找元素
2014/09/06 Javascript
浅谈JSON.stringify()和JOSN.parse()方法的不同
2016/08/29 Javascript
JavaScript“尽快失败”的原则实例详解
2016/10/08 Javascript
AngularJS控制器之间的通信方式详解
2016/11/03 Javascript
100多个基础常用JS函数和语法集合大全
2017/02/16 Javascript
Angular2使用jQuery的方法教程
2017/05/28 jQuery
基于js中document.cookie全面解析
2017/09/14 Javascript
详解Chai.js断言库API中文文档
2018/01/31 Javascript
Vue打包后出现一些map文件的解决方法
2018/02/13 Javascript
基于rollup的组件库打包体积优化小结
2018/06/18 Javascript
Vue程序调试的方法
2019/06/17 Javascript
vue使用video.js进行视频播放功能
2019/07/18 Javascript
vue-admin-template配置快捷导航的代码(标签导航栏)
2020/09/04 Javascript
vue-cli3项目配置eslint代码规范的完整步骤
2020/09/10 Javascript
[42:20]2014 DOTA2华西杯精英邀请赛5 24 DK VS NewBee
2014/05/25 DOTA
详解Python中heapq模块的用法
2016/06/28 Python
Python的shutil模块中文件的复制操作函数详解
2016/07/05 Python
python的unittest测试类代码实例
2017/12/07 Python
利用Python实现手机短信监控通知的方法
2019/07/22 Python
纯CSS3实现图片无间断轮播效果
2016/08/25 HTML / CSS
使用HTML5 Geolocation实现一个距离追踪器
2018/04/09 HTML / CSS
amazeui时间组件的实现示例
2020/08/18 HTML / CSS
后勤园长自我鉴定
2013/10/17 职场文书
护士试用期自我鉴定
2014/02/08 职场文书
八一建军节活动方案
2014/02/10 职场文书
安全生产汇报材料
2014/02/17 职场文书
广告设计应届生求职信
2014/03/01 职场文书
青年志愿者活动总结
2014/04/26 职场文书
法院反腐倡廉心得体会
2014/09/09 职场文书
抗洪救灾感谢信
2015/01/22 职场文书
Django显示可视化图表的实践
2021/05/10 Python
vue css 相对路径导入问题级踩坑记录
2022/06/05 Vue.js