事件捕获和事件冒泡
当你监听一个事件的触发的时候,它会经历三个状态,第一个是捕获阶段,第二个是目标节点,第三个是冒泡阶段,画个图来表示一下。
当我们触发某个DOM的监听事件的时候,捕获阶段会从外向内找到这个DOM节点,一般会在冒泡阶段执行监听事件。也就是说,当我们有如下这样的父子孙节点的时候,同时在父子孙身上都绑定有监听事件,它的打印顺序应该是1,2,3:那么怎样才能让我们在事件的捕获阶段就执行监听事件呢?那么就要提到addEventListener的参数了,它有三个参数,分别是event Type,callback,Boolean。分别代表着事件类型,回调函数,是否在事件捕获阶段就执行回调函数,默认为false,当我们把它设为true的时候它就表示会在事件捕获阶段执行回调函数:
grandson.addEventListener('click', grandsonEvent, true)
son.addEventListener('click',sonEvent, true)
father.addEventListener('click',fatherEvent, true)
那么这就完成了在事件捕获阶段去执行回调函数。接下来我们来考虑一下如何将事件冒泡给禁止,因为有时候事件冒泡会对我们的业务代码有不好的影响。
首先是w3c的方法是event.stopPropagation(),如果在目标元素上设置这个的话,就会阻止目标元素的事件冒泡到父级元素。如:
grandson.addEventListener('click', grandsonEvent)
son.addEventListener('click',() => {
sonEvent()
event.stopPropagation()
})
father.addEventListener('click',fatherEvent)
我们在son的回调函数里面使用了event.stopPropagrtion(),阻止它进一步的冒泡到father盒子上,所以最后打印结果是1,2.
那么事件冒泡能给我们带来什么好东西或者方便的东西吗?那肯定是有的,也就是我们常说的事件委托。
事件委托/事件代理
首先介绍一下我个人理解的事件委托的意思,就是将子组件要完成的回调函数绑定到父组件上面,然后由父组件代为调用。比如这个例子,每点击一个格子就要显示出它的颜色:
<style>
ul li {
width: 100px;
height: 200px;
}
.purple {
background-color: rgb(170, 74, 170);
}
.pink {
background-color: pink;
}
.skyblue {
background-color: skyblue;
}
.aqua {
background-color: aqua;
}
.gray {
background-color: gray;
}
ul {
display: flex;
list-style: none;
text-align: center;
height: 300px;
background-color: red;
}
</style>
</head>
<body>
<ul>
<li class="purple">紫色</li>
<li class="pink">粉红色</li>
<li class="skyblue">天蓝色</li>
<li class="aqua">青色</li>
<li class="gray">灰色</li>
</ul>
</body>
<script>
let ul = document.querySelector('ul')
ul.addEventListener('click', (event) => {
console.log(event.srcElement.innerHTML);
})
</script>
行百里者半九十