JavaScript中的事件冒泡、事件捕获、事件委托

DOM事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。

在这里插入图片描述
Dom标准事件流的触发的先后顺序为:先捕获再冒泡。即当触发dom事件时,会先进行事件捕获,捕获到事件源之后通过事件传播进行事件冒泡。
addEventListener的第三个参数
在我们平常用的addEventListener方法中,一般只会用到两个参数,一个是需要绑定的事件,另一个是触发事件后要执行的函数,然而addEventListener还可以传入第三个参数:

	element.addEventListener(event, function, useCapture);

第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数。如果不写第三个参数则默认在事件冒泡阶段调用事件处理函数。

下面先介绍事件冒泡:

事件冒泡

事件冒泡(dubbed bubbling):当一个元素接收到事件的时候,会把他接收到的事件传给自己的父级,一直到 window (注意这里传递的仅仅是事件,例如click、focus等等这些事件, 并不传递所绑定的事件函数。)
事件源 =>根节点(由内到外)进行事件传播。
举例说明:

在这里插入图片描述
给三个盒子依次绑定点击事件,当点击盒子的时候,会依次触发父级元素的点击事件。

	let big = document.querySelector('.big')
	let center = document.querySelector('.center')
	let small = document.querySelector('.small')
	big.addEventListener('click', () => {
	  console.log('big')
	})
	center.addEventListener('click', () => {
	  console.log('center')
	})
	small.addEventListener('click',()=>{
	  console.log('small')
	})

输出如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果父元素没有绑定点击事件则只会触发点击盒子的事件。

	let big = document.querySelector('.big')
	let center = document.querySelector('.center')
	let small = document.querySelector('.small')
	// big.addEventListener('click', () => {
	//   console.log('big')
	// })
	// center.addEventListener('click', () => {
	//   console.log('center')
	// })
	small.addEventListener('click', () => {
	  console.log('small')
	})

在这里插入图片描述
如果子元素(small)的点击事件去掉,当我们点击small的时候会把当前操作的点击事件传递给父元素(因为父元素绑定了点击函数)

	let big = document.querySelector('.big')
	let center = document.querySelector('.center')
	let small = document.querySelector('.small')
	big.addEventListener('click', () => {
	  console.log('big')
	})
	center.addEventListener('click', () => {
	  console.log('center')
	})
	// small.addEventListener('click', () => {
	//   console.log('small')
	// })

在这里插入图片描述
有些时候我们不希望产生事件冒泡,所以可以 在子事件中加入e.stopPropagation() 取消冒泡

	small.addEventListener('click', e => {
	  e.stopPropagation() // 阻止冒泡
	  console.log('small')
	})

这是时候再次点就,其他绑定了点击事件的父元素就不会再响应了
在这里插入图片描述

事件捕获

事件捕获(event capturing): 当鼠标点击或者触发dom事件时(被触发dom事件的这个元素被叫作事件源),浏览器会从根节点 =>事件源(由外到内)进行事件传播。
事件捕获与事件冒泡是比较类似的,最大的不同在于事件传播的方向。
还是举上面的例子:
tips; 因为事件冒泡是默认的,所以不做特殊处理

	let big = document.querySelector('.big')
	let center = document.querySelector('.center')
	let small = document.querySelector('.small')
	big.addEventListener('click', () => {
	  console.log('big-----事件捕获')
	}, true)
	center.addEventListener('click', () => {
	  console.log('center-----事件捕获')
	}, true)
	small.addEventListener('click', e => {
	  // e.stopPropagation() // 阻止冒泡
	  console.log('small-----事件捕获')
	}, true)
	big.addEventListener('click', () => {
	  console.log('big-----事件冒泡')
	})
	center.addEventListener('click', () => {
	  console.log('center-----事件冒泡')
	})
	small.addEventListener('click', e => {
	  // e.stopPropagation() // 阻止冒泡
	  console.log('small-----事件冒泡')
	},)

输出如下
在这里插入图片描述

事件委托

事件委托也称为事件代理。就是利用事件冒泡,把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托就无法实现。

不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。

应用场景:1000个button需要注册点击事件

如果循环给每个按钮添加点击事件,那么会增加内存损耗,影响性能

	let btns = document.getElementsByTagName('button');
	console.log(btns);
	for (let i = 0; i < btns.length; i++) {
	  btns[i].addEventListener('click', function () {
	    console.log(i);
	  })
	}

此时可以给button的父元素添加点击事件

let btnFather = document.getElementById('btnfather');
btnFather.addEventListener('click', function () {
  console.log(e.target.innerHTML)
}

这时相当于每个按钮都绑定了点击事件

优点:

  1. 替代循环绑定事件的操作,减少内存消耗,提高性能。比如:

     在table上代理所有td的click事件。
     在ul上代理所有li的click事件。
    
  2. 简化了dom节点更新时,相应事件的更新。比如:

     不用在新添加的li上绑定click事件。
     当删除某个li时,不用移解绑上面的click事件。
    

缺点:

  1. 事件委托基于冒泡,对于不冒泡的事件不支持。
  2. 层级过多,冒泡过程中,可能会被某层阻止掉。
  3. 理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在table上代理td,而不是在document上代理td。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/145363.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【NI-DAQmx入门】多通道数据采集

1.通道扩展解释 通道扩展是扩展数据采集设备的通道以包含另一个设备的通道的过程&#xff0c;从而有效地创建具有更多通道的任务。当使用通道扩展时&#xff0c;DAQmx 自动在 DAQmx 驱动程序级别路由触发器和时钟&#xff0c;以便多个设备同步。为了使设备作为一个整体运行&…

【STM32/FreeRTOS】SysTick定时器及FreeRTOS系统节拍

目录 一、SysTick定时器 1、SysTick寄存器介绍 &#xff08;1&#xff09;控制及状态寄存器 &#xff08;2&#xff09;重装载数值寄存器 &#xff08;3&#xff09;当前数值寄存器 2、SysTick寄存器配置函数 二、FreeRTOS中的SysTick定时器 1、SysTick配置函数及分析 …

软件工程分析报告07测试计划书——基于Paddle的肝脏CT影像分割

目录 测试计划书 1. 引言 2. 测试目标 3. 测试方法 3.1 黑盒测试 (1)等价类划分&#xff1a; (2)边界值分析&#xff1a; (3)因果图&#xff1a; ​编辑&#xff08;4&#xff09;错误推测法 3.2 白盒测试 测试用例&#xff01;&#xff01; 4. 测试环境 5. 测试计划 6…

【C++历险记】STL之set详解

个人主页&#xff1a;兜里有颗棉花糖&#x1f4aa; 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【C之路】&#x1f48c; 本专栏旨在记录C的学习路线&#xff0c;望对大家有所帮助&#x1f647;‍ 希望我们一起努力、成长&…

C++中关于多线程并发访问实例函数与静态函数

问题 1 C中多个线程共同执行一个实例函数&#xff0c;该函数是在线程的栈空间吗&#xff1f;对于函数中的多线程共享变量又是存储在哪里呢&#xff1f; example: 在该例子中线程绑定当前对象(this)的实例函数captureVideo, 并将int参数传递过去。但是对于captureVideo中多个线…

双写绕过 [极客大挑战 2019]BabySQL 1

打开题目 随便输入账号密码 根据报错信息可知这是单引号的字符型注入 那我们试试万能密码 1 or 11 页面报错 1 or 11 页面报错 而且根据报错内容显示是没有我们注入上去的or的 那我们就试试 1 order by 3 # 页面报错&#xff0c;根据报错显示页面过滤掉了or和by 那我们…

酷柚易汛ERP-购货订单操作指南

1、应用场景 先下购货订单&#xff0c;收货入库后生成购货单。 2、主要操作 2.1 新增购货订单 打开【购货】-【购货订单】新增购货订单。&#xff08;*为必填项&#xff0c;其他为选填&#xff09; ① 录入供应商&#xff1a;点击供应商字段框的 &#xff0c;在弹框中选择供…

新版本Idea设置启动参数

1.进入配置页面 2.点击下图红框的部分&#xff0c;会看到有很多操作可选 3.选择添加VM参数即可 此时就会多出一个可以输入参数的框了&#xff0c;如下&#xff1a;

第 1 章 概述 习题

1-1 因特网的前身是 1969 年创建的第一个分组交换网&#xff08;&#xff09;。 A. internet B. Internet C. NSFNET D. ARPANET 【答案】 D 【解析】 1-2 因特网上的数据交换方式是&#xff08;&#xff09;。 A. 电路交换 B. 报文交换 C. 分组交换 D. 光交换 【答…

springcloud旅游网站源码

开发技术&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;idea&#xff0c;nodejs&#xff0c;vscode springcloud springboot mybatis vue 功能介绍&#xff1a; 用户端&#xff1a; 登录注册 首页显示搜索景区&#xff0c;轮播图&#xff0c;旅游攻略列表 点击攻…

计算机毕业设计选题推荐-体育赛事微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

echarts 地图点位图标为动图,且可以多个不同图标

根据项目需求,echarts地图点位图标要是动图,且可以设置不同图标,经过多方查找,找到解决方案,可以用svg使gif动起来 let myChartChina echarts.init(document.getElementById("myChartChina"), "transparent", {renderer: "svg"});其中transpare…

线程池参数该怎么配置?这可能是为数不多的好答案

前言 CPU 密集型 CPU 核数 1 IO 密集型 CPU 核数 * 2 相信这个公式可谓是线程池八股文中老生常谈的万能公式了&#xff0c;但现实却很骨感&#xff0c;我之前有个系统就是按照这个公式算出来的参数去配置的。结果效果并不好&#xff0c;甚至让下游系统直呼受不了。这个东西…

阶段七-Day01-SpringMVC

一、Sping MVC的介绍 1. 使用Front(前端)设计模式改写代码 1.1 目前我们的写法 目前我们所写的项目&#xff0c;持久层、业务层的类都放入到Spring容器之中了。他们之间需要注入非常方便&#xff0c;只需要通过Autowired注解即可。 但是由于Servlet整个生命周期都是被Tomca…

并查集详解(附例题和模板)

一、并查集 &#xff08;1&#xff09;处理问题的类型 1.将两个集合合并 2.询问两个元素是否在一个集合当中 询问 1.fa[x]a; 2.if(fa[x]fa[y]) o(1) 在o(1)的复杂度内进行两个操作 &#xff08;2&#xff09;基本原理 基本原理&#xff1a;每个集合用一棵树来表示&#…

振南技术干货集:深入浅出的Bootloader(5)

注解目录 1、烧录方式的更新迭代 1.1 古老的烧录方式 (怀旧一下&#xff0c;单片机高压烧录器。) 1.2 ISP 与ICP 烧录方式 (还记得当年我们玩过的 AT89S51?) 1.3 更方便的 ISP 烧录方式 1.3.1串口 ISP &#xff08;是 STC 单片机成就了我们&#xff0c;还是我们成就了…

破解tomcat密码并上传webshell

tomcat基础认证爆破 暴力破解 进入vulnhub的tomcat8目录&#xff0c;启动环境 由于tomcat密码默认最大尝试错误次数为5次&#xff0c;需要修改server.xml&#xff0c;修改下面字段 failureCount"10000000000" lockOutTime"0"tomcat默认界面&#xff0c;…

一个破单机,也要用远程缓存?

大家好&#xff0c;豆小匠终于开始Coding了&#xff0c;这期来聊聊实战相关的杂谈。 正文开始&#xff01; 作为编程萌新的时候&#xff0c;总想着把程序做复杂&#xff0c;堆技术栈。 但是程序是为场景服务的&#xff0c;比如&#xff0c;我想提高接口的响应速度&#xff0c…

传输层协议-UDP协议

目录 传输层再谈端口号端口号范围划分认识知名端口号 UDP协议UDP协议格式UDP数据封装UDP数据分用 UDP协议的特点面向数据报 UDP缓冲区UDP使用注意事项基于UDP的应用层协议 传输层 实际上我们应用层的数据并不是直接发给网络的&#xff0c;而是需要先将数据发送给传输层&#xf…