先上一张图来描述下冒泡与捕获~~

上图描述了两个div,div1及其子节点div2。我把冒泡理解为当触发div2的点击事件时,程序默认也会触发div1的点击事件,但事件触发的开始点是在最内部的节点,是由内而外的顺序(如上图向上箭头);捕获的概念刚好和冒泡相反。当你点击内部div2时,事件触发的开始点是最外部的节点,是由外而内的顺序(如上图向下箭头);

关于阻止冒泡网上有很多方法,大部分是建议ie下阻止冒泡用cancelBubble,标准下用stopPropagation,因为ie低版本不兼容stopPropagation,奇怪的是经测试发现cancelBubble在IE各个版本和标准下都兼容。此处贴两段测试代码。

<style>
	div{border:1px solid #000;width:100px; padding: 5px; overflow: hidden;}
</style>
<div id="div1">
   div1
  <div id="div2">div2</div>
</div>
<script type="text/javascript">
   var oDiv1 = document.getElementById("div1");
   var oDiv2 = document.getElementById("div2");
   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);
   }
</script>

运行测试上面代码  点击div2后,先触发div2的事件,后触发了div1的事件

<style>
	div{border:1px solid #000;width:100px; padding: 5px; overflow: hidden;}
</style>
	<div id="div1">
	   div1
	  <div id="div2">div2</div>
	</div>
	<script type="text/javascript">
	   var oDiv1 = document.getElementById("div1");
	   var oDiv2 = document.getElementById("div2");
	   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);
	   }
	</script>

运行测试上面代码 点击div2后,只触发div2的事件

经过两段代码的对比测试发现,cancelBubble确实是全部兼容。cancelBubble字面意思是阻止泡沫,stopPropagation字面意思是阻止传播,貌似cancelBubble是特定用来阻止冒泡的。下面再测试下捕获的情况。IE低版本不支持捕获机制,且事件绑定方式需要用attachEvent做兼容,这里就不展开了,直接用addEventListener绑定事件。

<style>
  div{border:1px solid #000;width:100px; padding: 5px; overflow: hidden;}
</style>
<div id="div1">
   div1
  <div id="div2">div2</div>
</div>
<script type="text/javascript">
   var oDiv1 = document.getElementById("div1");
   var oDiv2 = document.getElementById("div2");
   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);
   }
</script>

运行测试上面代码 捕获模式下,点击div2,先触发div1的事件,后触发div2的事件

<style>
    div{border:1px solid #000;width:100px; padding: 5px; overflow: hidden;}
</style>
    <div id="div1">
       div1
      <div id="div2">div2</div>
    </div>
    <script type="text/javascript">
       var oDiv1 = document.getElementById("div1");
       var oDiv2 = document.getElementById("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);
       }
    </script>

运行测试上面代码 cancelBubble只在ff中可以阻止捕获,即点击div2后只触发了div1的事件。

<style>
    div{border:1px solid #000;width:100px; padding: 5px; overflow: hidden;}
</style>
<div id="div1">
   div1
  <div id="div2">div2</div>
</div>
<script type="text/javascript">
   var oDiv1 = document.getElementById("div1");
   var oDiv2 = document.getElementById("div2");
       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);
   }
</script>

运行测试上面代码 点击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遗留下的功能。

兼容的趋势应该是冒泡和捕获都被传播所替代了,传播既能阻止从外而内的,也能阻止从内而外的。至此我终于貌似可能好像有点不晕了。。。以上观点为个人观点和个人脑补的记录方式,欢迎交流指正 : )

点赞 (0)

欢迎转载:转载时请注明本文出处及文章链接