本文探讨同一元素绑定多个事件处理函数时,传入各函数的Event对象是否全等。分析表明,jQuery中通过liveHandler机制确保全等;原生addEventListener在Firefox等非IE浏览器中全等,而IE的attachEvent在冒泡事件中,通过window.event获取的对象与参数传递的对象不一致。
此前曾遇到此类问题,但未进行总结。
如今再次遇到,为获取准确结论,特记录如下:
问题定义与jQuery实现机制
核心问题:同一事件绑定多个处理函数时,各函数接收的Event对象是否完全相等?
具体场景示例:
相关代码片段如下:
dom.addEvent('click',fna);
dom.addEvent('click',fnb); 问题1:若在fna中对Event对象添加属性,后续执行的fnb能否访问该属性?
问题2:执行fna和fnb时传入的Event对象是否全等,即 Eventfna === Eventfnb 是否成立?
标准文档篇幅较长,未仔细查阅其中关于此规则的具体说明,此处暂略。
对于jQuery,同一事件绑定的多个处理函数接收的Event对象是全等的。
在jQuery live绑定事件的实现中,针对可能被重复执行的liveHandler,通过额外给Event对象添加liveFired属性,使得在第一次执行后的liveHandler开始即退出:
相关判断逻辑如下:
if (event.liveFired === this || ...) {
return;
}
///....
event.liveFired = this; 测试验证:
测试代码如下:
function a(e) {
e.abc = function() {
alert(a);
};
prevEvent = e;
prevIeEvent=window.event;
}
function b(e,event) {
e.abc(); //fn
alert(e === prevEvent); //true
if(event=window.event){
alert(event===e); //false
alert(event===prevIeEvent);//false
alert(event===prevEvent);//false
}
}
var t = document.getElementById("p");
if (t.addEventListener) {
t.addEventListener('click', a, false);
t.addEventListener('click', b, false)
} else {
t.attachEvent('onclick', b);
t.attachEvent('onclick', a)
} 原生绑定与IE浏览器差异分析
对于原生绑定事件方式[addEventListener,attachEvent],同一节点上多个处理函数间通过参数传递的Event对象是全等的。但在IE浏览器中,通过window.event形式获取的Event对象与参数传递的对象不全等,且不同处理函数间通过window.event获取的对象也不全等。
冒泡事件中的对象全等性验证
针对冒泡事件的情况:
相关代码示例:
dom.addEvent('click',fna);
domParentNode.addEvent('click',fnb); 在jQuery中,通过trigger触发事件时,冒泡事件各处理函数间的Event对象是全等的。但由用户实际行为触发的事件,则不是同一对象,自定义属性也无法传递,对取值和设置的修改不影响真正的originalEvent。
采用原生绑定事件方式[addEventListener,attachEvent]的情况:
测试代码如下:
function a(e) {
e.abc = function() {
alert(a);
};
prevEvent = e;
prevIeEvent=window.event;
}
function b(e,event) {
alert(e.abc); //fn
alert(e === prevEvent); //true
if(event=window.event){
alert(event===e); //false
alert(event===prevIeEvent);//false
alert(event===prevEvent);//false
}
}
var t = document.getElementById("p");
if (t.addEventListener) {
t.addEventListener('click', a, false);
document.body.addEventListener('click', b, false);
} else {
t.attachEvent('onclick', a);
document.body.attachEvent('onclick', b);
} 结果显示,在IE中使用attachEvent绑定冒泡事件时,各处理函数内的Event对象不一致。而在Firefox等浏览器中,使用addEventListener则保持对象全等。
事实上,在非IE浏览器中,事件传播过程中的处理函数,或同一DOM节点触发的多个函数间的Event对象是全等的,这与绑定形式[addEventListener/DOM0]无关。
而在IE浏览器中,仅同一DOM节点触发的多个函数间通过参数传递的Event对象(attachEvent)是全等的。