事件冒泡
微软提出的事件流叫事件冒泡,也就是说事件的传播为:从事件开始的具体元素,一级级往上传播到较为不具体的节点。案例如下:
<div id="outer">
<p id="inner">Click me!</p>
</div>
当我们点击P元素时,事件是这样传播的:
- p
- div
- body
- html
- document
现代浏览器都支持事件冒泡
事件捕获
网景团队提出的另一种事件流叫做事件捕获。它的原理刚好和事件冒泡相反,它的用意在于事件到达预定目标之前捕获它,而最具体的节点应该是最后才接收到事件的。
比如上面的案例,事件的传播方向就变成了这样:
- document
- html
- body
- div
- p
目前主流浏览器也支持这种事件流模型,但是老版本浏览器不支持,所以很少人使用事件捕获,而是用事件冒泡多一点。
DOM事件流
“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。
首先发生的事件捕获,为截获事件提供机会。然后是实际的目标接受事件。最后一个阶段是事件冒泡阶段,可以在这个阶段对事件作出相应。以前面的例子,则会按下图顺序触发事件。
在DOM事件流中,事件的目标在捕获阶段不会接收到事件。这意味着在捕获阶段,事件从document到p后就停止了
下一个阶段是处于目标阶段,于是事件在p上发生,并在事件处理中被看成冒泡阶段的一部分。然后冒泡阶段发生。
多数支持DOM事件流的浏览器都实现了一种特定的行为;即使“DOM2级事件”规范明确要求捕获阶段不会涉及事件目标,但浏览器都会在捕获阶段触发事件对象上的事件。结果就是有两个机会在目标对象上操作事件。
addEventListener 的第三个参数
“DOM2级事件”中规定的事件流同时支持了事件捕获阶段和事件冒泡阶段,而作为开发者,我们可以选择事件处理函数在哪一个阶段被调用。
addEventListener方法用来为了一个特定的元素绑定一个事件处理函数,是js中常用的方法。addEventListener有三个参数:
element.addEventListener(event, function, useCapture)
事件代理
在实际的开发中,利用事件流的特性,我们可以使用一种叫做事件代理的方法。
<ul class="color_list">
<li>red</li>
<li>orange</li>
<li>yellow</li>
<li>green</li>
<li>blue</li>
<li>purple</li>
</ul>
<div class="box"></div>
.color_list{
display: flex;
display: -webkit-flex;
}
.color_list li{
width: 100px;
height: 100px;
list-style: none;
text-align: center;
line-height: 100px;
}
//每个li加上对应的颜色,此处省略
.box{
width: 600px;
height: 150px;
background-color: #cccccc;
line-height: 150px;
text-align: center;
}
我们想要点击每个li
标签时,输出li
当中的颜色(innerHTML
)。常规做法是遍历每个li
,然后在每个li
上绑定一个点击事件:
var color_list=document.querySelector(".color_list");
var colors=color_list.getElementsByTagName("li");
var box=document.querySelector(".box");
for(var n=0;n<colors.length;n++){
colors[n].addEventListener("click",function(){
console.log(this.innerHTML)
box.innerHTML="该颜色为 "+this.innerHTML;
})
}
这种做法在li
较少的时候用可以使用,加入很多个li
就会导致降低性能。
这时就需要事件代理出场了,利用事件流的特性,我们只绑定一个事件处理函数也可以完成:
function colorChange(e){
var e=e||window.event;//兼容性的处理
if(e.target.nodeName.toLowerCase()==="li"){
box.innerHTML="该颜色为 "+e.target.innerHTML;
}
}
color_list.addEventListener("click",colorChange,false)
由于事件冒泡机制,点击了li
后悔冒泡到ul
,此时就会触发绑定在ul
上的点击事件,再利用target
找到事件实际发生的元素,就可以达到预期的效果。
使用事件代理的好处不仅在于将多个事件处理函数减为一个,而且对于不同的元素可以有不同的处理方法。加入上述列表当中添加了其他的元素节点,我们不必再一次循环给每个元素绑定事件。
冒泡还是捕获?
对于事件代理来说,在时间捕获或者事件冒泡阶段处理并没有明显的优劣之分,但是由于事件冒泡的事件流模型被所有主流的浏览器兼容,从兼容性角度还是推荐事件冒泡模型。
阻止事件冒泡和阻止默认事件
$("#div1").mousedown(function(e){
var e=event||window.event;
event.stopPropagation();
});
event.preventDefault( )
网友评论