冒泡机制
先看图:
事件捕获
当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素
这个过程中,事件相应的监听函数是不会被触发的
到达该目标元素节点后,触发该元素事件,如果没有绑定事件则不执行
事件冒泡
- 从目标元素开始,往顶层元素传播
- 途中如果有节点绑定了相应的事件处理函数,这些函数都会被触发。
捕获和冒泡的执行顺序
<div id='div1'>
div1
<div id='div2'>
div2
<div id='div3'>div3</div>
</div>
</div>
let div1 = document.getElementById('div1')
let div2 = document.getElementById('div2')
let div3 = document.getElementById('div3')
div1.addEventListener('click', () => {
console.log('div1 bubble')
})
div2.addEventListener('click', () => {
console.log('div2 bubble')
})
div3.addEventListener('click', () => {
console.log('div3 bubble')
})
div1.addEventListener('click', () => {
console.log('div1 capture')
}, true)
div3.addEventListener('click', () => {
console.log('div3 capture')
}, true)
div2.addEventListener('click', () => {
console.log('div2 capture')
}, true)
- 点击div3,发现结果为 div1 capture => div2caputre => div3 bubble => div3 bubble => div2 bubble=> div1 bubble 也就是说目标元素是先执行的冒泡,再执行的捕获。其余的都是先捕获后冒泡~ 这是因为目标元素是事件触发主体处于事件流中的目标阶段,处理事件的顺序是根据注册顺序来执行的
事件委托
- 当大量子节点需要绑定事件处理的时候,管理起来较为麻烦,因此可以委托给父元素来进行统一的管理
- 并且可以方便地动态添加和修改元素,不需要因为元素的改动而修改事件绑定
应用
ui里有多个li,当某个li点击的时候,打印出该li的值
如果每个li添加点击事件当然也可以,但是不能统一管理,并且添加或者减少li元素的时候,可能会造成内存泄露
解决方式是给ul添加点击事件
<ul id="ul1">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
window.onload = function () {
var oUl = document.getElementById('ul1');
//这里给ul添加事件
var oUl = document.getElementById('ul1');
oUl.addEventListener('click', function(e){
if(e.target.nodeName === 'LI') {
console.log(e.target.innerHTML)
}
})
}
防止冒泡事件
- event.stopPropagation(); // 阻止了事件冒泡,但不会阻击默认行为
- event.preventDefault(); //阻止默认事件,比如a的跳转事件