# 示例场景
设定两个嵌套事件
<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)
}
})