当前位置: 首页 > news >正文

深度剖析JavaScript中冒泡和捕获机制、事件代理

   JS事件传播的两种机制包括冒泡和捕获,下面将具体剖析它们之间本质的区别。


   事件冒泡: 先触发子元素的事件,再触发父元素的事件。


   创建一个 ul label 和 li label, 分别绑定一个父id 和 子 id, 再通过创建 script,去绑定各自的点击事件。



在这里插入图片描述



<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><ul id="father">我是一个无序列表<li id="son">1个列表项</li></ul><script>document.getElementById('father').onclick = function(){console.log('我点击了父元素');}document.getElementById('son').onclick = function(){console.log('我点击了子元素');}</script>
</body></html>


   当我点击 "第1个列表项"后,在Console先输出的是 “我点击了子元素”, 然后是 “我点击了父元素”, 可见冒泡的执行顺序是由里向外,也就是从 li - ul - body - document - window 这样的执行顺序,就好比人扔了一块石头去河里,先是冒一个小泡,再逐个现成大的水泡这种扩散现象。因此,JS默认的点击事件就是冒泡。



在这里插入图片描述



   事件捕获: 先触发父元素的事件,再触发子元素的事件。如果要将冒泡改为捕获,需要添加监听事件。监听事件的第3个参数必须为 “true”, 默认为 false 。



在这里插入图片描述



<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><ul id="father">我是一个无序列表<li id="son">1个列表项</li></ul><script>// document.getElementById('father').onclick = function(){//     console.log('我点击了父元素');// }document.getElementById('father').addEventListener('click',function(){console.log('我点击了父元素');},true);document.getElementById('son').onclick = function(){console.log('我点击了子元素');}</script>
</body></html>


    再点击 "第1个列表项"后,控制台先输出的是 “我点击了父元素”, 然后是 “我点击了子元素”, 可见捕获的执行顺序是由外向里,也就是从 window - documment - body - ul - li 这样的执行顺序。



在这里插入图片描述



    事件代理是指利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。


    先复制多几个 li label



在这里插入图片描述



<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><ul id="father">我是一个无序列表<li id="son">1个列表项</li><li id="son">2个列表项</li><li id="son">3个列表项</li><li id="son">4个列表项</li><li id="son">5个列表项</li></ul><script>// document.getElementById('father').onclick = function(){//     console.log('我点击了父元素');// }document.getElementById('father').addEventListener('click',function(){console.log('tesing for 事件代理');},true);// document.getElementById('son').onclick = function(){//     console.log('我点击了子元素');// }</script>
</body></html>


   例如然后点击 “第5个列表项”,由于冒泡作用,当点击到 li label,冒泡到 ul label 上,执行了 ul label上的点击事件,最后在 Console 输出了 “tesing for 事件代理”。



在这里插入图片描述



在这里插入图片描述



   通常父级那么多子元素,怎样去区分事件本应该是哪个子元素呢?在 function() 函数里面添加一个 event param, 稍后在Console打印这个 event 的 object



在这里插入图片描述



   例如当点击 “第4个列表项” 后,就会输出了 event 这个 object



在这里插入图片描述



   点击 “target” 继续展开后续的内容

在这里插入图片描述



   展开后,可见还有省略的内容,点击 “…” 这个省略的位置后,可以继续展示余下隐藏的内容。



在这里插入图片描述



   展开后,可见 textContent : “第4个列表项”



在这里插入图片描述



   添加判断条件为 点击 "第4个列表项"时,才会打印 “tesing for 事件代理”, 点击其它元素没有任何内容输出。



在这里插入图片描述



<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><ul id="father">我是一个无序列表<li id="son">1个列表项</li><li id="son">2个列表项</li><li id="son">3个列表项</li><li id="son">4个列表项</li><li id="son">5个列表项</li></ul><script>// document.getElementById('father').onclick = function(){//     console.log('我点击了父元素');// }document.getElementById('father').addEventListener('click',function(event){if (event.target.textContent === "第4个列表项"){console.log('tesing for 事件代理');};// console.log(event);},true);// document.getElementById('son').onclick = function(){//     console.log('我点击了子元素');// }</script>
</body></html>


   怎么取消冒泡或者捕获 ? 通过 event.stopPropagation() 方法可以实现。



在这里插入图片描述



<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><ul id="father">我是一个无序列表<li id="son">1个列表项</li><!-- <li id="son">2个列表项</li><li id="son">3个列表项</li><li id="son">4个列表项</li><li id="son">5个列表项</li> --></ul><script>// document.getElementById('father').onclick = function(){//     console.log('我点击了父元素');// }// document.getElementById('father').addEventListener('click',function(event){// //     if (event.target.textContent === "第4个列表项"){// //     console.log('tesing for 事件代理');// //     };// //     // console.log(event);// // },true);// document.getElementById('son').onclick = function(){//     console.log('我点击了子元素');// }document.getElementById('father').addEventListener('click',function(event){console.log('testing for click father element');});document.getElementById('son').addEventListener('click',function(event){console.log('testing for click son element');event.stopPropagation();});</script>
</body></html>


   再次点击 “第1个列表项” 后,只执行子元素输出 “testing for click son element”,不再执行父元素, 也就是不再输出 “testing for click father element”, 取消了冒泡。



在这里插入图片描述

相关文章:

  • 升级Xcode15,iOS17后问题解决
  • FFmpeg的AVcodecParser
  • leetcode:457. 环形数组是否存在循环
  • 微信小程序---使用npm包安装Vant组件库
  • qemu 虚拟机
  • 互质数(函数)
  • 实战经验:如何利用房产小程序提升客户满意度?
  • 分页操作中使用LIMIT和OFFSET后出现慢查询的原因分析
  • C++中的继承(一)
  • Ubuntu22.04添加用户
  • Android - 分区存储 MediaStore、SAF
  • uniapp - 简单版本自定义tab栏切换
  • 黑客(网络安全)技术自学30天
  • C++类与对象 (上)
  • 《opencv实用探索·十六》opencv直方图计算calcHist函数解析
  • 【mysql】环境安装、服务启动、密码设置
  • 4. 路由到控制器 - Laravel从零开始教程
  • C++11: atomic 头文件
  • C学习-枚举(九)
  • docker-consul
  • input的行数自动增减
  • Java|序列化异常StreamCorruptedException的解决方法
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • JavaScript设计模式之工厂模式
  • oldjun 检测网站的经验
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • TypeScript实现数据结构(一)栈,队列,链表
  • 编写符合Python风格的对象
  • 工程优化暨babel升级小记
  • 聊聊redis的数据结构的应用
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 模型微调
  • 小程序开发之路(一)
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • # Apache SeaTunnel 究竟是什么?
  • #LLM入门|Prompt#3.3_存储_Memory
  • #stm32驱动外设模块总结w5500模块
  • (1)(1.11) SiK Radio v2(一)
  • (30)数组元素和与数字和的绝对差
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (二)springcloud实战之config配置中心
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (十一)图像的罗伯特梯度锐化
  • (一)搭建springboot+vue前后端分离项目--前端vue搭建
  • (转)关于多人操作数据的处理策略
  • (转载)OpenStack Hacker养成指南
  • .“空心村”成因分析及解决对策122344
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .net oracle 连接超时_Mysql连接数据库异常汇总【必收藏】
  • .NET 解决重复提交问题
  • .NET 设计模式初探