话很少说,先附上W3C连接:www.w3.org/TR/DOM-Leve…
javascript
如今,咱们就能够知道,DOM事件流的三个阶段是先捕获阶段,而后是目标阶段,最后才是冒泡阶段。咱们时常面试所说的先捕获后冒泡也由此而来。事件代理就是利用事件冒泡或事件捕获的机制把一系列的内层元素事件绑定到外层元素。 html
实际操做中,咱们能够经过 element.addEventListener() 设置一个元素的事件模型为冒泡事件或者捕获事件。
先来看一下 addEventListener 函数的语法:java
element.addEventListener(type, listener, useCapture)
复制代码
<div id="a" style="width: 100%; height: 300px;background-color: antiquewhite;">
a
<div id="b" style="width: 100%; height: 200px;background-color: burlywood;">
b
<div id="c" style="width: 100%; height: 100px;background-color: cornflowerblue;">
c
</div>
</div>
</div>
<script> var a = document.getElementById('a') var b = document.getElementById('b') var c = document.getElementById('c') //注册冒泡事件监听器 a.addEventListener('click', () => {console.log("冒泡a")}) b.addEventListener('click', () => {console.log('冒泡b')}) c.addEventListener('click', () => {console.log("冒泡c")}) </script>
复制代码
当咱们点击c时,执行结果以下:
面试
<div id="a" style="width: 100%; height: 300px;background-color: antiquewhite;">
a
<div id="b" style="width: 100%; height: 200px;background-color: burlywood;">
b
<div id="c" style="width: 100%; height: 100px;background-color: cornflowerblue;">
c
</div>
</div>
</div>
<script> var a = document.getElementById('a') var b = document.getElementById('b') var c = document.getElementById('c') //注册捕获事件监听器 a.addEventListener('click', () => {console.log("捕获a")}, true) b.addEventListener('click', () => {console.log('捕获b')}, true) c.addEventListener('click', () => {console.log("捕获c")}, true) </script>
复制代码
当咱们点击c时,运行结果以下:
函数
咱们将上述的代码a,b,c三个元素都注册捕获和冒泡事件,并以元素c做为触发事件的主体,即事件流中的目标阶段。ui
<div id="a" style="width: 100%; height: 300px;background-color: antiquewhite;">
a
<div id="b" style="width: 100%; height: 200px;background-color: burlywood;">
b
<div id="c" style="width: 100%; height: 100px;background-color: cornflowerblue;">
c
</div>
</div>
</div>
<script> var a = document.getElementById('a') var b = document.getElementById('b') var c = document.getElementById('c') a.addEventListener('click', () => {console.log("冒泡a")}) b.addEventListener('click', () => {console.log('冒泡b')}) c.addEventListener('click', () => {console.log("冒泡c")}) a.addEventListener('click', () => {console.log("捕获a")}, true) b.addEventListener('click', () => {console.log('捕获b')}, true) c.addEventListener('click', () => {console.log("捕获c")}, true) </script>
复制代码
a,b,c三个元素都是先注册冒泡事件再注册捕获事件,当咱们点击c时,执行结果又是如何?请看下图。
url
咱们将上图中c元素的事件注册调换一下顺序,就能够知道目标阶段执行事件的顺序了,以下图:
spa
咱们知道了事件冒泡和事件捕获的原理,那么对于事件委托就比较容易理解了。
重复一遍,**事件代理就是利用事件冒泡或事件捕获的机制把一系列的内层元素事件绑定到外层元素。**至于为何一般咱们说事件代理是利用事件冒泡的机制来实现的,只是你们习觉得常而已。代理
<ul id="item-list">
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
</ul>
复制代码
对于上述的列表元素,咱们但愿将用户点击了哪一个item打印出来,一般咱们能够给每一个item注册点击事件监听器,可是须要对每一个元素进行事件监听器的注册;可是经过事件代理,咱们能够将多个事件监听器减小为一个,这样就减小代码的重复编写了。
利用事件冒泡或事件捕获实现事件代理:code
var items = document.getElementById('item-list');
//事件捕获实现事件代理
items.addEventListener('click', (e) => {console.log('捕获:click ',e.target.innerHTML)}, true);
//事件冒泡实现事件代理
items.addEventListener('click', (e) => {console.log('冒泡:click ',e.target.innerHTML)}, false);
复制代码
当点击列表中的item时,执行结果以下:
以上的东西总结起来就是有如下几点:
一直不理解事件流的模型为何是先捕获后冒泡?直到看到第一张图的那个Window,才明白为何是先捕获后冒泡了。由于Window对象是直接面向用户的,那么用户触发一个事件,如点击事件,确定是用window对象开始的,因此天然就是先捕获后冒泡啦。