最近在做一个直播间的项目,涉及到很多点击效果,多层元素之间的点击使我踩了不少坑,故重新整理一翻。
注:以下示例代码使用Vue.js编写
事件监听
对一特定事件(比如点击)进行监听,当发生时去做一些希望做的事情,这就做事件监听。
事件传播
事件传播指的是发生事件时传播的过程。一共按顺序分为以下三个阶段。
- 捕获阶段:从
window
对象传导到目标节点(从上到下)的过程 - 目标阶段:在当前目标触发的过程
- 冒泡阶段:从目标节点传导回到
windowd
对象(从下到上)的过程
这里我们写一个例子去体验传播的过程,分别在div
和p
分别都添加两个点击事件,一个是捕获的点击事件,一个普通的点击事件。
<html>
<body>
<div id="app">
<h1>测试事件传播</h1>
<div @click.capture="clickEl" @click="clickEl">
<p @click.capture="clickEl" @click="clickEl">点击</p>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
phases: {
1: 'capture',
2: 'target',
3: 'bubble'
},
},
methods: {
clickEl (e) {
alert(`当前元素:${e.currentTarget.tagName}, 阶段:${this.phases[e.eventPhase]}`);
}
}
})
</script>
</body>
</html>
复制代码
点击页面上的“点击”,弹出四次弹窗结果分别:
1.当前元素:DIV, 阶段:capture
2.当前元素:P, 阶段:target
3.当前元素:P, 阶段:target
4.当前元素:DIV, 阶段:bubble
复制代码
从结果看出,点击P元素后,事件传播顺序:捕捉阶段从DIV
到P
,在P
上就是目标阶段,最后到P
到DIV
是冒泡阶段。
实际上,事件传播的最上层对象是window
,接着依次是document
,html(document.documentElement)
和body(document.body)
。也就是说,上例的事件传播顺序,详细地说,在捕获阶段依次为window、document、html、body、div、p
,在冒泡阶段依次为p、div、body、html、document、window
。
事件使用例子
懂得事件传播后,可以根据捕捉、冒泡等特点去进行更好写出更好的代码,或者加速我们解决问题,以下是一些网上整理的只是和我自己遇到的问题,欢迎补充。
事件代理(delegation)
事件代理是利用子元素向上冒泡的特点,通过在父元素添加监听事件对多个子元素的统一处理。
以下是一个事件代理的例子:
<html>
<body>
<div id="app">
<h1>测试事件代理</h1>
<ul @click="clickEl">
<li>项目1</li>
<li>项目2</li>
<li>项目3</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var vm = new Vue({
el: '#app',
methods: {
clickEl (e) {
if (e.target.tagName.toLowerCase() === 'li') {
// do something
}
}
}
})
</script>
</body>
</html>
复制代码
停止捕获
有时候希望在父节点就停止向下传播事件,这时可以使用:
<div @click.capture.stop="clickEl">
....
<div/>
复制代码
如果是希望,某些条件下才停止向下传播,这是应该将停止步骤单独在方法调用:
<div @click.capture="clickEl">
....
<div/>
methods: {
clickEl (e) {
// code...
if (条件1) {
e.stopPropagation();
}
}
}
复制代码
停止冒泡
有时候希望在子节点就停止向上冒泡,这时可以使用:
<div @click="clickDiv">
@click.stop="clickP">点击</p>
</div>
复制代码
如果是希望,某些条件下才停止向上冒泡播,这是应该将停止步骤单独在方法调用:
<div @click="clickDiv">
@click="clickP">点击</p>
</div>
methods: {
clickP (e) {
// code...
if (条件1) {
e.stopPropagation();
}
}
....
}
复制代码
总结
事件监听在不同的项目都是需要的,但都有不同的需求。但只要对事件传播机制有一定的理解,更容易找到合适的方法去实现或者解决问题。