写点什么

Web 前端入门:JavaScript 事件冒泡与事件捕获

  • 2025-07-02
    福建
  • 本文字数:2882 字

    阅读完需:约 9 分钟

在讨论冒泡和捕获之前,先看这么一段代码:


<style>  .bd {    border: 1px solid #000;    padding: 8px;  }</style>
<div id="container1" class="bd"> 外层 <div id="container2" class="bd"> 内层 <div id="container3" class="bd"> 最内层 <div id="container4" class="bd"> 按钮 </div> </div> </div></div>
<script> (() => { const container1 = document.querySelector('#container1') const container2 = document.querySelector('#container2') const container3 = document.querySelector('#container3') const container4 = document.querySelector('#container4') container1.addEventListener('click', () => { console.log('container1') }) container2.addEventListener('click', () => { console.log('container2') }) container3.addEventListener('click', () => { console.log('container3') }) container4.addEventListener('click', () => { console.log('container4') }) })()</script>
复制代码


页面渲染大概长这样:



点击最里面的 按钮 元素,按照思维惯例,是否应该先执行 container1 的点击事件??毕竟 container1 是最外层,而且也是最先绑定事件的元素。

然而控制台输出结果为:


container4container3container2container1
复制代码


有点出乎意料是吧,为什么先执行的是 container4 呢?


事件冒泡


JS 绑定的事件默认是冒泡规则,什么意思呢?可以理解为:触发事件后就像水里面有一个泡泡,在水底慢慢的往上冒,从触发事件的目标元素开始,经过一层一层的盒模型,分别触发盒模型身上绑定的事件。


所以上面代码中,在点击 按钮 时,先触发了本身绑定的 click 事件,再一层一层往外传播,最终就打印出了控制台输出的结果。


事件捕获


注意:仅默认状态下,事件是冒泡规则,在绑定事件时候,可以修改第三个配置参数改为由外向内传播,这种传播顺序就是 事件捕获 。


以上面代码为蓝本,仅添加 addEventListener 的第三个参数为 true,就将绑定规则改为了 事件捕获 。如下:


container1.addEventListener('click', () => {  console.log('container1')}, true)container2.addEventListener('click', () => {  console.log('container2')}, true)container3.addEventListener('click', () => {  console.log('container3')}, true)container4.addEventListener('click', () => {  console.log('container4')}, true)
复制代码


还是点击 按钮,上面代码执行结果:


container1container2container3container4
复制代码


事件捕获还有另一种写法,第三个参数可以传入一个对象,通过对象的 capture 属性设置为事件捕获。


container1.addEventListener('click', () => {  console.log('container1')}, {  // 另一种设置事件捕获方式  capture: true,})
复制代码


冒泡与捕获顺序


既然同一个事件有冒泡与捕获,那么冒泡与捕获的顺序如何?上例子:


container1.addEventListener('click', () => {  console.log('冒泡:', 'container1')})container2.addEventListener('click', () => {  console.log('冒泡:', 'container2')})container3.addEventListener('click', () => {  console.log('冒泡:', 'container3')})container4.addEventListener('click', () => {  console.log('冒泡:', 'container4')})container1.addEventListener('click', () => {  console.log('捕获:', 'container1')}, true)container2.addEventListener('click', () => {  console.log('捕获:', 'container2')}, true)container3.addEventListener('click', () => {  console.log('捕获:', 'container3')}, true)container4.addEventListener('click', () => {  console.log('捕获:', 'container4')}, true)
复制代码


同时给元素绑定两种事件,点击 按钮 执行结果:


捕获: container1捕获: container2捕获: container3捕获: container4冒泡: container4冒泡: container3冒泡: container2冒泡: container1
复制代码


到这里已经可以得出结论:JS 的事件传播会经历三个阶段,由 事件捕获 开始,传递到 目标元素 之后,就改为 事件冒泡,冒泡阶段完了之后事件结束。


阻止事件传播


既然事件有传播,那程序就有办法阻止事件传播。所有事件执行时都有一个 event 对象,此对象中有方法可用于阻止事件传播。

示例:


container1.addEventListener('click', () => {  console.log('冒泡:', 'container1')})container2.addEventListener('click', () => {  console.log('冒泡:', 'container2')})container3.addEventListener('click', () => {  console.log('冒泡:', 'container3')})container4.addEventListener('click', () => {  console.log('冒泡:', 'container4')})container1.addEventListener('click', (event) => {  event.stopPropagation()  console.log('捕获:', 'container1')}, true)container2.addEventListener('click', () => {  console.log('捕获:', 'container2')}, true)container3.addEventListener('click', () => {  console.log('捕获:', 'container3')}, true)container4.addEventListener('click', () => {  console.log('捕获:', 'container4')}, true)
复制代码


注意 event.stopPropagation() 这个方法,此方法是阻止事件传播的关键。


以上代码在 container1 这个元素上就阻止了事件传播,所以点击 按钮 之后,仅 container1 会执行,其他所有元素都不会再触发,结果:

捕获: container1
复制代码

调用 event.stopPropagation() 就是告诉 JS,事件到此为止,不再继续了。


event 对象其他常用方法和属性:


event.target:触发事件的原始元素。event.currentTarget:当前绑定事件的元素(等同于 this)。event.type:事件类型(如 "click")。event.preventDefault():阻止默认行为(如表单提交、链接跳转、自定义右键菜单)。event.stopPropagation():阻止事件冒泡。event.stopImmediatePropagation():阻止同一元素的其他监听器执行。event.x 和 event.y:鼠标点击位置的坐标。


在事件中要使用 this 获取元素时,必须使用 function 函数,使用箭头函数绑定的事件 this 将会指向外层作用域的 this 指针,如下代码中箭头函数 this 指向的是 Window :


<div id="container4" class="bd">  按钮</div>
<script> (() => { const container4 = document.querySelector('#container4') container4.addEventListener('click', () => { console.log(this) // Window 对象 }) container4.addEventListener('click', function () { console.log(this) // div#container4 }) })()</script>
复制代码


写在最后


编程中的细节问题,总是越挖掘越心惊,学得越来越多,才会发现知道的越来越少。


文章转载自:前端路引

原文链接:https://www.cnblogs.com/linx/p/18959113

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
Web前端入门:JavaScript 事件冒泡与事件捕获_JavaScript_不在线第一只蜗牛_InfoQ写作社区