先上一张图来描述下冒泡与捕获~~
上图描述了两个div,div1及其子节点div2。我把冒泡理解为当触发div2的点击事件时,程序默认也会触发div1的点击事件,但事件触发的开始点是在最内部的节点,是由内而外的顺序(如上图向上箭头);捕获的概念刚好和冒泡相反。当你点击内部div2时,事件触发的开始点是最外部的节点,是由外而内的顺序(如上图向下箭头);
关于阻止冒泡网上有很多方法,大部分是建议ie下阻止冒泡用cancelBubble,标准下用stopPropagation,因为ie低版本不兼容stopPropagation,奇怪的是经测试发现cancelBubble在IE各个版本和标准下都兼容。此处贴两段测试代码。
<div id="div1"> div1 <div id="div2">div2</div> </div>
var oDiv1 = document.getElementById("div1"); var oDiv2 = document.getElementById("div2"); oDiv1.onclick = function(ev){ alert(this.innerHTML); } oDiv2.onclick = function(ev){ alert(this.innerHTML); }
---><--- 点击div2后,先触发div2的事件,后触发了div1的事件
oDiv1.onclick = function(ev){
alert(this.innerHTML);
}
oDiv2.onclick = function(ev){
oEv = ev || window.event;
//oEv.stopPropagation(); //阻止冒泡(ff,chrome,ie高版本都可以阻止冒泡)
oEv.cancelBubble = true; //阻止冒泡(全兼容)
alert(this.innerHTML);
}
---><--- 点击div2后,只触发div2的事件
经过两段代码的对比测试发现,cancelBubble确实是全部兼容。cancelBubble字面意思是阻止泡沫,stopPropagation字面意思是阻止传播,貌似cancelBubble是特定用来阻止冒泡的。下面再测试下捕获的情况。IE低版本不支持捕获机制,且事件绑定方式需要用attachEvent做兼容,这里就不展开了,直接用addEventListener绑定事件。
function fn1(){
alert(this.innerHTML);
}
oDiv1.addEventListener("click",fn1,true);//第三个参数默认为false(冒泡模式),true为捕获模式
oDiv2.onclick = function(ev){
oEv = ev || window.event;
//oEv.stopPropagation(); //阻止冒泡(ff,chrome,ie高版本都可以阻止冒泡)
oEv.cancelBubble = true; //阻止冒泡(全兼容)
alert(this.innerHTML);
}
---><--- 捕获模式下,点击div2,先触发div1的事件,后触发div2的事件
function fn1(ev){
oEv = ev || window.event;
oEv.cancelBubble = true; //尝试阻止捕获,chrome和ie高版本下不能阻止捕获,ff可以
alert(this.innerHTML);
}
oDiv1.addEventListener("click",fn1,true);//第三个参数默认为false(冒泡模式),true为捕获模式
oDiv2.onclick = function(ev){
oEv = ev || window.event;
//oEv.stopPropagation(); //阻止冒泡(ff,chrome,ie高版本都可以阻止冒泡)
oEv.cancelBubble = true; //阻止冒泡(全兼容)
alert(this.innerHTML);
}
---><--- cancelBubble只在ff中可以阻止捕获,即点击div2后只触发了div1的事件。
function fn1(ev){
oEv = ev || window.event;
//oEv.cancelBubble = true; //尝试阻止捕获,chrome和ie高版本下不能阻止捕获,ff可以
oEv.stopPropagation(); //尝试阻止捕获,ff,chrome,ie高版本都可以阻止捕获
alert(this.innerHTML);
}
oDiv1.addEventListener("click",fn1,true);//第三个参数默认为false(冒泡模式),true为捕获模式
oDiv2.onclick = function(ev){
oEv = ev || window.event;
//oEv.stopPropagation(); //阻止冒泡(ff,chrome,ie高版本都可以阻止冒泡)
oEv.cancelBubble = true; //阻止冒泡(全兼容)
alert(this.innerHTML);
}
---><--- 点击div2后只触发了div1的事件 (ff,chrome,ie高版本都可以阻止捕获)
上面的测试结果有点晕,我整理下。
一、在冒泡的情况下:
1.用cancelBubble阻止冒泡时,ff,chrome,ie各版本都可以阻止冒泡
2.用stopPropagation阻止冒泡时,ff,chrome,ie高版本可以阻止冒泡
二、在捕获的情况下:
1.用cancelBubble阻止捕获时,chrome和ie高版本下不能阻止捕获,ff可以 ( IE6,7,8不行,不支持捕获功能 )
2.用stopPropagation阻止捕获时,ff,chrome,ie高版本都可以阻止捕获 ( IE6,7,8不行,不支持捕获功能 )
这兼容性实在让人看不懂...我只能自己脑补下原因了:
早期ff和ie都支持cancelBubble阻止冒泡这种情况。但ff比ie要先进点,它还支持了用cancelBubble阻止捕获的情况,后来ff觉得不管是冒泡还是捕获模式,都可以理解为传播。因此ff引入了关键词stopPropagation来同时阻止冒泡和捕获,而且保留了cancelBubble也能同时阻止冒泡和捕获的功能。
与此同时IE经过发展,到了IE9版本时也支持了ff的那套stopPropagation阻止冒泡和捕获的功能,但IE觉得没有必要将ff保留的cancelBubble阻止捕获的功能也实现,毕竟那只是ff遗留下的功能。至于chrome,它更接近ff,但chrome可能早期并没有用cancelBubble实现过捕获功能,因此它在捕获上和IE一样,摒弃了ff遗留下的功能。
兼容的趋势应该是冒泡和捕获都被传播所替代了,传播既能阻止从外而内的,也能阻止从内而外的。至此我终于貌似可能好像有点不晕了。。。以上观点为个人观点和个人脑补的记录方式,欢迎交流指正 : )