事件冒泡 :当一个元素接收到事件的时候 会把他接收到的事件传给自己的父级,一直到window (注意这里传递的仅仅是事件,什么是事件呢不是函数哦,一开始看见这个自己理解的是函数,反复琢磨事件指的是click、focus等等这些事件, 并不传递所绑定的事件函数。)
举例说明:
<style>
#div1{
border: 1px solid #000000;
width: 200px;
height: 100px;
}
#div2{
border: 1px solid #cccccc;
width: 100px;
height: 50px;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2"></div>
</div>
<script>
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
div2.onclick = function(){alert(1);};
div1.onclick = function(){alert(2);}; //父亲
</script>
</body>
代码很简单,就是两个父子关系的div,然后分别加了点击事件,当我们在div2里面点击的时候,会发现弹出了一次1,接着又弹出了2,这说明点击的时候,不仅div2的事件被触发了,它的父级的点击事件也触发了,这种现象就叫做冒泡。点击了div2的同时会把点击事件传递给自己父级,因为父级元素也绑定着click事件,所以触发弹出2;如果父元素div1没有绑定点击函数则只是弹出1,不触发任何操作
如果子元素的点击事件去掉,当我们点击div2的时候弹出2,把当前操作的点击事件传递给了 父元素,因为父元素绑定了点击函数所以触发弹框。
这里我们要注意,我们传递的仅仅是事件触发,也就是说当点击div2仅仅触发了父级的点击事件,并没有把自己的绑定的函数给父级,父级的执行情况,取决于自己所绑定的函数,如果这里它绑定的函数是空,自然没什么表现。
<style>
#div1{
border: 1px solid #000000;
width: 200px;
height: 100px;
position: relative;
top: 50px;
}
#div2{
border: 1px solid #cccccc;
width: 100px;
height: 50px;
position:relative;
top:-50px;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2"></div>
</div>
<script>
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
div2.onclick = function(){alert(1);}; //子元素
div1.onclick = function(){alert(2);}; //父亲
</script>
修改div1,div2的位置, 同样上面的代码也会触发两次弹框分别弹出2和1,说明事件冒泡与div显示的位置无关,至于html源码中的位置有关系
冒泡事件有优点自然也有缺点,比如下面的例子
以上是执行过程,如果不用f12工具调试,我们会发现灰色区域一直都是显示状态,调试过程中发现是隐藏了一下的,只是事件执行太快了,很快又执行了document的点击事件,让面板隐藏;
我们来分析下代码,当点击div2的时候,他会触发父级的点击事件,然后一层一层的往上传,所以document的点击事件自然也被触发了,最后就是我们看到的效果又变成block状态了
那么这个时候我们肯定不希望有冒泡了,所以解决办法就是取消冒泡了:(后来补充)
取消事件冒泡有两种方式:
标准的W3C 方式:e.stopPropagation();这里的stopPropagation是标准的事件对象的一个方法,调用即可
非标准的IE方式:ev.cancelBubble=true; 这里的cancelBubble是 IE事件对象的属性,设为true就可以了
通常我们会封装这样一个函数:
function stopBubble(e) { //如果提供了事件对象,则这是一个非IE浏览器 if ( e && e.stopPropagation ) //因此它支持W3C的stopPropagation()方法 e.stopPropagation(); else //否则,我们需要使用IE的方式来取消事件冒泡 window.event.cancelBubble = true; }
这个时候需要用到事件对象里的 cancelBubble属性,把它设为true即可,ev.cancelBubble=true;所以改进后的代码如下:<script>
var div2 = document.getElementById("div2"); var div1 = document.getElementById("div1"); div2.onclick = function(ev){ // 红色面板加事件 div1.style.display = "block"; stopBubble(ev);//这样就不会再冒泡给父级了 }; document.onclick = function(){ div1.style.display = "none"; }
function stopBubble(e) { //如果提供了事件对象,则这是一个非IE浏览器 if ( e && e.stopPropagation ) //因此它支持W3C的stopPropagation()方法 e.stopPropagation(); else //否则,我们需要使用IE的方式来取消事件冒泡 window.event.cancelBubble = true; }
其实冒泡还有一大优点,就是事件委托,而且经常用到,还能提高很大的性能