[整理]js中的事件捕获与事件冒泡

作者 likaiqiang 日期 2017-03-15
[整理]js中的事件捕获与事件冒泡

什么是DOM树

每个HTML页面都是一颗DOM树,浏览器在解析HTML代码时,会按照代码结构将代码解析成一颗树状结构,每个HTML标签对应DOM树上相应的结点。

比如下面的代码:

<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id='c1'>
<ul>
<li><a href="#">点我</a></li>
</ul>
</div>
</body>
</html>

对应的DOM树为:

什么是事件捕获与事件冒泡

以上图为例,我们给div添加一个事件响应函数

var c1=document.getElementById('c1');
c1.addEventListener('click',function(e){
console.log(e.target.nodeName)
});

当点击“点我”的时候,浏览器就会寻找发生点击事件的事件源,从上到下,依次找到body->div->ul->li->a
这个从上到下寻找事件源的过程就叫做事件捕获。

找到了事件源a标签,a标签上的点击事件就会像泡泡一样传递到它的上一级li,进而传递到ul、div、body,这个与事件捕获传递方向相反的过程就叫做事件冒泡。

在事件冒泡过程中,不管该节点有没有绑定事件响应函数,冒泡都会继续,当a标签上的点击事件传递到div上时,div上有点击事件响应函数,然后就会执行这个函数,console.log(e.target.nodeName),输出事件源。

同样的点击li、ul、div也会执行类似过程,这样就可以只用一个响应函数来处理4次不同的点击事件。

取消事件冒泡
使用event对象的stopPropagation() 方法

如果在a、li、ul这三个节点任一节点上使用stopPropagation() 方法,冒泡过程就会终止,div就监听不到点击事件,它的响应函数也不会执行

var li=c1.getElementsByTagName('li')[0];
li.addEventListener('click',function(e){
console.log(this.tagName);
e.stopPropagation();
})

在li上取消事件冒泡,这时再点击a标签,事件传递到li上就会停止,console.log只会输出li而不会输出a。

如果点击的是ul标签,console.log会输出ul,这是另外一个点击事件,中间没有取消冒泡,妥妥的被div捕捉到