# 示例场景

设定两个嵌套事件

<div id="outer">
    <button id="inner"></button>
</div>

事件处理

// 外部事件outer
document.getElementById('outer').addEventListener('click', function(e) {
  console.log(e.target.tagName)
})
// 内部事件inner
document.getElementById('inner').addEventListener('click', function(e) {
  console.log(e.target.tagName)
})

# 事件冒泡和事件捕获

对有父元素的元素,当触发某个事件时,比如点击,此时不同浏览器对该事件的处理机制有两种,事件冒泡和事件捕获。

# 事件冒泡

浏览器处理事件的顺序由内而外,就像水中的气泡从内向外冒出来。

上面这个示例在事件冒泡下:

  • 首先检查inner元素是否注册了click事件,如果有则执行。
  • 接着继续检查inner的父元素是否注册了click事件。。。直到到达html元素。
  • 打印顺序为:button: click = inner—>div: click = outer—>body,html

# 阻止事件冒泡

点击内部子元素触发事件冒泡,但是不想事件传递出去,可以使用以下函数阻止事件冒泡。

e.preventDefault();

# 事件捕获

浏览器处理事件的顺序由外到内,和事件冒泡相反。

上面这个示例在事件捕获下:

  • 检查html是否注册了click事件,有则执行。
  • 检查下一个祖先元素是否注册了click事件,直到到达实际点击部位。
  • 在此例中为body,html—>div: click = outer—>button: click = inner

# 用事件冒泡还是事件捕获?

事件冒泡和事件捕获都被收录为w3c的规范,目前浏览器默认处理事件采用事件冒泡机制,要想更改为事件捕获机制,需要在addEventListener第三个参数置为true。

# 事件委托

利用冒泡原理,允许将子节点事件委托在父节点上。

<ul id="myUl">
<li>学号001</li>
<li>学号002</li>
<li>学号003</li>
</ul>

点击每个li,触发相同的处理逻辑,此时只需将li的事件委托在父节点ul上。

document.getElementById('myUl').addEventListener('click', function(e) {
  if(e.target.tagName === 'LI') {
      alert(e.target.innerText)
  }
})
# 参考资料

事件介绍