事件流
事件触发包含三个阶段:捕获阶段、目标阶段和冒泡阶段,也被称为事件流。
- 捕获阶段:事件从window对象传导到事件目标,从最外层的祖先元素开始往下传递,直到达到事件目标元素,即事件传播到目标元素的父级元素时停止传播。捕获阶段的主要作用是为了在事件到达目标元素之前捕获到事件,常用于在事件到达目标元素之前对事件做出拦截或处理。
- 目标阶段:事件到达目标元素时触发,即事件到达目标元素的最内层的祖先元素时停止传播。
- 冒泡阶段:事件从目标元素传导回window对象,从目标元素开始往上冒泡,直到达到document对象或window对象为止。冒泡阶段的主要作用是让事件处理器可以在目标元素之外的元素上对事件做出响应。
一般情况下,事件处理器会在目标阶段或者冒泡阶段进行处理。如果想要在捕获阶段处理事件,需要在添加事件监听器时,将useCapture参数设置为true。
- 例如:
document.addEventListener('click', function() { console.log('冒泡阶段处理事件'); }); document.addEventListener('click', function() { console.log('捕获阶段处理事件'); }, true);
事件委托
事件委托是一种常用的优化前端事件处理的技术。在事件委托中,不是在每个子元素上单独添加事件监听器,而是将事件监听器添加到它们的父元素上,利用事件冒泡的机制,通过判断事件源的类型,执行对应的操作。
举个例子,如果我们想为一个列表中的每个项添加点击事件,通常的做法是循环遍历每个项,给它们单独绑定点击事件监听器。但是如果列表中的项很多,这么做的代价就比较高。此时,我们可以将点击事件委托给列表的父元素,并在父元素上添加一个点击事件监听器。当用户点击某个列表项时,该事件就会冒泡到父元素,我们只需要判断事件源的类型是否为列表项,然后执行对应的操作即可。
-
html代码:
<ul id="list"> <li>列表项1</li> <li>列表项2</li> <li>列表项3</li> <li>列表项4</li> <li>列表项5</li> </ul>
-
js代码:
const list = document.getElementById('list'); list.addEventListener('click', (event) => { const target = event.target; if (target.tagName === 'LI') { console.log(`您点击了列表项:${target.textContent}`); } });
事件委托的优点是:
减少了事件绑定次数,提高了性能;
动态添加的元素可以直接拥有事件,无需进行额外的绑定操作;
可以解决事件绑定和删除时可能出现的内存泄漏问题。
需要注意的是,如果父元素上有多个事件监听器,那么每个监听器都会执行,因此要注意阻止事件冒泡或停止事件传播,以免引起意外结果。
事件截断
事件截断指的是在事件传播过程中,阻止事件继续传播或冒泡。在DOM树中,事件传播分为三个阶段:捕获阶段、目标阶段和冒泡阶段。可以通过事件对象的方法来控制事件传播的行为。
- html代码
<div id="parent"> <div id="child"></div> </div>
在捕获阶段触发的事件,可以通过事件对象的 stopPropagation() 方法来阻止事件继续传播到目标阶段和冒泡阶段。
- 例如:
const parent = document.getElementById('parent'); const child = document.getElementById('child'); parent.addEventListener('click', function (event) { console.log('parent clicked'); }, true); // 捕获阶段触发 child.addEventListener('click', function (event) { console.log('child clicked'); event.stopPropagation(); // 阻止事件继续传播 }, true); // 捕获阶段触发
在目标阶段触发的事件,可以通过事件对象的 stopPropagation() 方法来阻止事件继续冒泡到父元素。
- 例如:
const parent = document.getElementById('parent'); const child = document.getElementById('child'); parent.addEventListener('click', function (event) { console.log('parent clicked'); }); child.addEventListener('click', function (event) { console.log('child clicked'); event.stopPropagation(); // 阻止事件继续冒泡到父元素 });
除了 stopPropagation() 方法外,还可以使用 stopImmediatePropagation() 方法来阻止事件的继续传播,并且停止事件的冒泡和执行事件的默认行为。
- stopPropagation() 方法用于阻止事件的进一步传播,即停止冒泡。调用该方法后,事件不会再被分派到其他的节点上,但是仍然会在当前节点继续处理。例如:
document.addEventListener('click', function (event) { console.log('document clicked'); event.stopPropagation(); }, false); document.body.addEventListener('click', function (event) { console.log('body clicked'); }, false); document.querySelector('#my-button').addEventListener('click', function (event) { console.log('button clicked'); }, false);
当单击按钮时,事件会首先在文档对象上触发,然后停止冒泡。因此,body 元素上的 click 事件不会被触发,只有按钮上的 click 事件被触发。
- stopImmediatePropagation() 方法用于阻止事件的进一步传播,并且停止任何后续事件处理函数的执行。调用该方法后,事件不会再被分派到其他的节点上,并且当前节点上的其他事件处理函数也不会被执行。例如:
document.addEventListener('click', function (event) { console.log('document clicked'); }, false); document.body.addEventListener('click', function (event) { console.log('body clicked'); event.stopImmediatePropagation(); }, false); document.querySelector('#my-button').addEventListener('click', function (event) { console.log('button clicked'); }, false);
在上面的代码中,当单击按钮时,事件会首先在文档对象上触发,然后在 body 元素上触发。但是,由于在 body 元素上的事件处理函数调用了 stopImmediatePropagation() 方法,因此按钮上的事件处理函数不会被执行,也就是说,console.log(‘button clicked’) 不会被输出。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/199235.html