记得刚学JS时老师讲的事件冒泡:“鱼在水中吐泡泡,是在鱼所在的 深水区逐渐上升到水面”。就如这个例子一样,下面我总结一下我所理解的冒泡和捕获。
事件冒泡和事件捕获都是描述事件触发时序问题的术语,也就是事件流。 (简单说就是描述在页面中点击一个按钮时,是先执行这个节点的事件还是先执行这个节点父节点的事件,的顺序。)
事件冒泡
事件冒泡是自上而下的触发事件,也就是先执行我们触发的按钮所绑定的事件,执行完后,接着执行按钮父元素所绑定的事件。
<div id="one">
<ul id="two">
<li id="three">appel<li>
<li>orange</li>
<li>pear</li>
</ul>
</div>
var one =document.getElementById('one');
var two=document.getElementById('two');
var three=document.getElementById('three');
two.addEventListener('click',function(){
alert('2');
},false);
one.addEventListener('click',function(){
alert('1');
},false);
three.addEventListener('click',function(){
alert('3');
},false);
注意:这里的addEventListener方法的第三个参数为false就是事件冒泡,如果是true,就是我们下面要讲的事件捕获。
在这里如果先点击three,会依次弹出3、2、1,;如果先点击two,会依次弹出2、1;若点击one,只会弹出1。这就是事件冒泡。
事件捕获
事件捕获是和事件冒泡的顺序是相反的,也就是说我们把上面的addEventListener方法的第三个参数改为true,那么
var one =document.getElementById('one');
var two=document.getElementById('two');
var three=document.getElementById('three');
two.addEventListener('click',function(){
alert('2');
},true);
one.addEventListener('click',function(){
alert('1');
},true);
three.addEventListener('click',function(){
alert('3');
},true);
现在的结果是:当我点击three的时候,会依次弹出1、2、3,;当我点击two的时候,会依次弹出1、2;当我点击one的时候,只会弹出1。根据结果可以看出,弹出的顺序完全是跟冒泡相反的。
冒泡和捕获同时存在
如果在上述方法中,同时存在事件冒泡和事件捕获时,根据W3C的标准,会先执行捕获在执行冒泡。
如何在日常开发中用到事件冒泡和事件捕获
在上述HTML代码中可以看到,如果想实现鼠标移动到li上时背景变成灰色,就可以用到事件冒泡。
$("one").on("mouseover",function(e){
$(e.target).css("background-color","#ddd").siblings().css("background-color","white");
})
$("li").on("mouseover",function(){
$(this).css("background-color","#ddd").siblings().css("background-color","white");
})
上面两种方法都可以实现,第一种利用了事件冒泡。从代码量上来看,两种都差不多,但在执行时第二种比第一种多了遍历li的步骤,而且当动态添加一个li时,第一种是不需要重新绑定方法的,但第二种就要重新绑定了。这里就要引入另外一个JS中的要点:事件委托(事件代理)。事件委托就是利用事件冒泡的原理来执行的。当点击li时都会冒泡到最外层的div中,那么只要给div绑定一个方法,当点击里面的ul li时也都可以冒泡到最外层的div中,都会触发执行,这就是事件委托,委托它们的父级代为执行事件。
阻止事件委托和冒泡
上文中的target属性用来判断进行点击的元素。e.target表示在事件冒泡中触发事件的源元素,在IE浏览器中时e.srcElement。
e.stopPropagation()方法是阻止事件冒泡的,表示到我为止,我父亲和祖父的方法就别执行了。
//兼容IE
function stopPropagation(e) {
if (e.stopPropagation) {
e.stopPropagation();
} else {
window.event.cancelBubble = true;
}
}