关于javascript DOM事件模型的两件事


Posted in Javascript onJuly 22, 2010

事件捕捉(Event Capture)的实现问题

W3C DOM Level2的事件模型规范中,事件在DOM树中的传播过程(从根节点到目标节点)被分为了两个阶段:捕捉(Capture)和冒泡(Bubbling)。下面这个图能大概的说明整个过程:
关于javascript DOM事件模型的两件事
(from W3C)

如果想创建一个捕捉事件,在支持W3C 事件模型的浏览器中,将addEventListener的第三个参数设为true就好了。例如:

document.getElementById('foo').addEventListener('click',function(){alert('Hello, world!');},true);

前一阵因为想弄懂事件捕捉,所以做了点小实验,分别在Firefox 2、Safari 3 on Windows和Opera 9上实践了事件捕捉(当然,因为IE不支持事件捕捉,所以…),实验的原理见下图:
关于javascript DOM事件模型的两件事
ID为div1和div2的两个元素都被绑定了捕捉阶段的事件处理函数,这样:

当点击#div1(蓝色区域)时,应该会alert出”div1″
当点击#div2(黄色区域)时,应该会先alert出”div1″,再alert出”div2″,因为在事件捕捉阶段,事件是从根元素向下传播的,#div1是#div2的父元素,自然绑定在#div1上的click事件也会先于#div2上的click事件被执行。
然而,以上的设想只试用于Firefox 2和Safari 3 on Windows,在Opera 9中,事情会变成这样:

当点击#div1(蓝色区域)时,什么都不会发生
当点击#div2(黄色区域)时,会alert出”div1″,随后什么都不会再发生
可以看出,在Opera 9中,目标元素(TargetElement)的click事件没有被执行。通过Realazy(orz…)的指点,找到了这篇文章:《Event capture explained》,发现,原来Opera中的实现才是正确的。此文中有一段话如是说:

The DOM spec states that capturing events should not fire on target, because the idea of a capturing event is to detect events before they reach their targets. Because of bugs in Gecko and Safari, web content that is tested mostly with Firefox or other Gecko-based browsers sometimes expects capturing listeners to fire on target. Such content will fail in Opera 7, 8 and current releases of 9 because of its correct implementation of the standard.
大意是说:DOM规范中陈述了捕捉型的事件不应该在目标元素上被执行,因为捕捉型事件的用意就是为了监测到达目标元素之前的事件。Firefox和Safari的实现都是带有bug的。

再来看看W3C的DOM Events规范中的原话:

A capturing EventListener will not be triggered by events dispatched directly to the EventTarget upon which it is registered.
所以,在整个事件传播中,被执行的顺序是:

父元素中所有的捕捉型事件(如果有)自上而下地执行
目标元素的冒泡型事件(如果有)
父元素中所有的冒泡型事件(如果有)自下而上地执行
在了解了这些后,也许还是不要使用事件捕捉为妙,至少暂时不要。
IE的高级事件处理模型的问题
重复绑定
IE下没有addEventListener,但是也有自己的attachEvent,即所谓的Microsoft Model。二者的实现基本相同只是attachEvent的第一个参数(事件类型)需要加”on”,而addEventListener不用,另外attachEvent因为不支持事件捕捉,所以也没有第三个参数。

然而,attachEvent还有一个很要命的问题:重复绑定事件。(这是从ppk on JavaScript中学到的)

一个例子:

function sayHello(){ 
alert('Hello, world!'); 
} 
// W3C Model 
$('div1').addEventListener('click', sayHello, false); 
$('div1').addEventListener('click', sayHello, false); 
// Microsoft Model 
$('div1').attachEvent('onclick', sayHello); 
$('div1').attachEvent('onclick', sayHello);

在W3C模型中,相同事件处理函数的绑定会被忽略,也就是说第二个$('div1').addEventListener('click', sayHello, false);会被忽略。

而在Microsoft模型中,第二个$('div1').attachEvent('onclick', sayHello);同样会被执行,所以,当你点击#div1的时候,alert框会弹出来两次。更有甚者,在detachEvent时候,也同样要detachEvent两次才能彻底把sayHello从#div1的click事件中删除。

为什么不继续使用alertID()了?
这是因为IE的事件模型的另一个缺陷,在alertID中,使用了this关键字来指代被绑定了该事件处理函数的元素,这样,在W3C模型中,alertID中的this指代了#div1或者#div2。

但是在Microsoft模型中,缺少了对this的支持后,this.id就会变为undefined,因为这时候this指代了window对象。

Javascript 相关文章推荐
javascript截取字符串(通过substring实现并支持中英文混合)
Jun 24 Javascript
判断是否安装flash player及当前版本的JS代码
Aug 08 Javascript
javascript将数字转换整数金额大写的方法
Jan 27 Javascript
nw.js实现类似微信的聊天软件
Mar 16 Javascript
JavaScript中的数据类型转换方法小结
Oct 26 Javascript
ReactNative-JS 调用原生方法实例代码
Oct 08 Javascript
node.js版本管理工具n无效的原理和解决方法
Nov 24 Javascript
AngularJS使用ng-inlude指令加载页面失败的原因与解决方法
Jan 19 Javascript
解决Layui 表单提交数据为空的问题
Aug 15 Javascript
Vue框架里使用Swiper的方法示例
Sep 20 Javascript
vue+moment实现倒计时效果
Aug 26 Javascript
详解Howler.js Web音频播放终极解决方案
Aug 23 Javascript
JavaScript 事件系统
Jul 22 #Javascript
(function($){...})(jQuery)的意思
Jul 22 #Javascript
用js实现的模拟jquery的animate自定义动画(2.5K)
Jul 20 #Javascript
一个简单的js动画效果代码
Jul 20 #Javascript
dess中一个简单的多路委托的实现
Jul 20 #Javascript
js 返回时间戳所对应的具体时间
Jul 20 #Javascript
javascript 数据类型转换(parseInt,parseFloat)
Jul 20 #Javascript
You might like
discuz7 phpMysql操作类
2009/06/21 PHP
php设计模式 Delegation(委托模式)
2011/06/26 PHP
javascript 窗口加载蒙板 内嵌网页内容
2010/11/19 Javascript
仅img元素创建后不添加到文档中会执行onload事件的解决方法
2011/07/31 Javascript
关于js日期转化为毫秒数“节省20%的效率和和节省9个字符“问题
2012/03/01 Javascript
Javascript创建自定义对象 创建Object实例添加属性和方法
2012/06/04 Javascript
js重写alert控件(适合学习js的新手朋友)
2014/08/24 Javascript
JavaScript使用Max函数返回两个数字中较大数的方法
2015/04/06 Javascript
php利用curl获取远程图片实现方法
2015/10/26 Javascript
一步一步封装自己的HtmlHelper组件BootstrapHelper(三)
2016/09/14 Javascript
详解jquery validate实现表单验证 (正则表达式)
2017/01/18 Javascript
Javascript前端经典的面试题及答案
2017/03/14 Javascript
JavaScript实现前端分页控件
2017/04/19 Javascript
JQuery实现图片轮播效果
2017/05/08 jQuery
微信小程序实现表单校验功能
2020/03/30 Javascript
AngularJS下$http服务Post方法传递json参数的实例
2018/03/29 Javascript
jquery实现搜索框功能实例详解
2018/07/23 jQuery
vue2.0 路由模式mode="history"的作用
2018/10/18 Javascript
layer插件实现在弹出层中弹出一警告提示并关闭弹出层的方法
2019/09/24 Javascript
[50:17]Newbee vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
python分析作业提交情况
2017/11/22 Python
Python面向对象class类属性及子类用法分析
2018/02/02 Python
python深度优先搜索和广度优先搜索
2018/02/07 Python
Matplotlib 生成不同大小的subplots实例
2018/05/25 Python
Python使用分布式锁的代码演示示例
2018/07/30 Python
浅述python中深浅拷贝原理
2018/09/18 Python
Python 中使用 PyMySQL模块操作数据库的方法
2019/11/10 Python
基于CSS3实现立方体自转效果
2016/03/01 HTML / CSS
NBA欧洲商店(英国):NBA Europe Store UK
2018/07/27 全球购物
餐厅执行经理岗位职责范本
2014/02/26 职场文书
网吧最新创业计划书范文
2014/03/27 职场文书
关爱留守儿童标语
2014/06/18 职场文书
处级干部反四风个人对照检查材料思想汇报
2014/09/27 职场文书
工作经验交流材料
2014/12/30 职场文书
五四青年节活动总结
2015/02/10 职场文书
党员个人自我评价
2015/03/03 职场文书