事件,捕捉到触点
2023-10-01 17:54:43
当我们与网页交互时,诸如鼠标点击、移动、键盘按键等操作,都会引发一系列事件,而我们的浏览器会为这些操作指定相应的处理函数,并将它们排列在一个队列中,依次执行。
JavaScript为网页交互提供了多种事件监听方式,以完成界面逻辑开发,大致可以归纳为冒泡与捕获两种。这两种事件响应方式不同,适合不同的场景使用。
事件冒泡
我们先来看一下事件冒泡。简单说来,事件冒泡是指事件从子节点开始,向上沿着父节点链传播,直到到达根节点。
比如,我们有一个嵌套的 <div>
元素,子元素 <div>
在事件发生时,会首先触发它自己的事件监听函数,然后再依次触发祖先节点的事件监听函数,最后到达根节点时触发根节点上的事件监听函数,直到所有绑定该事件的监听函数都被触发完毕。
这种事件处理方式有利于捕获事件,尤其是在一些特殊的场景中,比如当子节点被隐藏或不可见时,仍然可以通过其父节点捕获到事件。
<div id="parent">
<div id="child">Click me</div>
</div>
const parent = document.getElementById('parent');
const child = document.getElementById('child');
// 父元素监听单击事件
parent.addEventListener('click', function() {
console.log('Parent clicked');
});
// 子元素监听单击事件
child.addEventListener('click', function(e) {
console.log('Child clicked');
// 阻止事件冒泡
e.stopPropagation();
});
在这个示例中,当我们点击子元素 <div>
时,子元素上的事件监听函数会首先被触发,输出 "Child clicked"。然后,事件会冒泡到父元素 <div>
,触发父元素上的事件监听函数,输出 "Parent clicked"。但是,由于我们在子元素的事件监听函数中调用了 e.stopPropagation()
,阻止了事件进一步冒泡,所以事件不会传播到根节点。
事件捕获
事件捕获与事件冒泡相反,事件从根节点开始向下传播,依次经过子孙节点,直到到达目标元素。
事件捕获的发生,依赖一个参数useCapture
来决定,此参数默认值为false,即冒泡。如果将其设置为true,则会以捕获的方式进行事件监听。
事件捕获一般不常使用,不过在特定场景下很有用,比如阻止事件冒泡。
<div id="parent">
<div id="child">Click me</div>
</div>
const parent = document.getElementById('parent');
const child = document.getElementById('child');
// 父元素监听单击事件,捕获阶段
parent.addEventListener('click', function() {
console.log('Parent clicked in capture phase');
}, true);
// 子元素监听单击事件,冒泡阶段
child.addEventListener('click', function(e) {
console.log('Child clicked');
// 阻止事件冒泡
e.stopPropagation();
});
在这个示例中,当我们点击子元素 <div>
时,父元素上的事件监听函数会首先被触发,输出 "Parent clicked in capture phase"。然后,事件会冒泡到子元素 <div>
,触发子元素上的事件监听函数,输出 "Child clicked"。由于我们在子元素的事件监听函数中调用了 e.stopPropagation()
,阻止了事件进一步冒泡,所以事件不会传播到根节点。
事件代理
事件代理(又称事件委托)是一种性能优化技术,它可以减少事件监听器的数量,提高页面的性能。事件代理的基本思想是,将事件监听器注册到父元素上,然后在父元素的事件处理函数中,根据事件目标元素来执行不同的操作。
事件代理的优势在于,可以减少事件监听器的数量,从而提高页面的性能。但是,事件代理也有一个缺点,就是事件处理函数可能变得比较复杂,而且在某些情况下,事件代理可能无法捕获到事件。
<div id="parent">
<div class="child">Click me</div>
<div class="child">Click me</div>
<div class="child">Click me</div>
</div>
const parent = document.getElementById('parent');
// 给父元素添加事件监听器
parent.addEventListener('click', function(e) {
// 判断事件目标元素是否为子元素
if (e.target.classList.contains('child')) {
console.log('Child clicked: ', e.target.innerHTML);
}
});
在这个示例中,我们给父元素 <div>
添加了一个事件监听器,当父元素发生点击事件时,事件处理函数会检查事件目标元素是否为子元素 <div>
。如果是,则输出子元素的文本内容。这样,我们就可以用一个事件监听器来处理所有子元素的点击事件,而无需为每个子元素分别添加事件监听器。
以上就是关于JavaScript事件机制的简单介绍。通过了解事件冒泡、事件捕获和事件代理,我们可以更灵活地处理用户的交互操作,构建出更加健壮、响应灵敏的web应用程序。