一、事件捕捉(event capture)的实现问题
首先在说这件事前,先感谢一下realazy。
w3c dom level2的事件模型规范中,事件在dom树中的传播过程(从根节点到目标节点)被分为了两个阶段:捕捉(capture)和冒泡(bubbling)。下面这个图能大概的说明整个过程:
(from w3c)
如果想创建一个捕捉事件,在支持w3c 事件模型的浏览器中,将addeventlistener的第三个参数设为true就好了。例如:
document.getelementbyid('foo').addeventlistener('click',function(){alert('hello, world!');},true);
前一阵因为想弄懂事件捕捉,所以做了点小实验,分别在firefox 2、safari 3 on windows和opera 9上实践了事件捕捉(当然,因为ie不支持事件捕捉,所以…),实验的原理见下图:
id为div1和div2的两个元素都被委派了捕捉阶段的事件处理函数,这样:
然而,以上的设想只试用于firefox 2和safari 3 on windows,在opera 9中,事情会变成这样:
可以看出,在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对象。
新闻热点
疑难解答