DOM--事件链、事件冒泡和捕获、事件代理

本文详细介绍了JavaScript的事件处理机制,包括事件的捕获阶段、目标阶段和冒泡阶段,以及如何通过addEventListener的第三个参数控制事件执行模式。此外,还探讨了阻止事件冒泡和系统默认事件的方法,并通过实例解析了事件代理的概念和应用场景,强调了事件代理在性能优化和处理动态元素中的优势。最后,通过一道面试题展示了事件捕获和冒泡的执行顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、事件链

事件的三个阶段:

捕获阶段:结构上(非视觉上)嵌套关系的元素,会存在事件捕获的功能,即同一事件自父元素捕获至子元素(事件源元素)(自顶向下)

目标阶段:事件不断传递直到目标节点,最终在目标节点上触发这个事件

冒泡阶段:结构上(非视觉上)嵌套关系的元素,会存在事件冒泡的功能,即同一事件自子元素冒泡向父元素(自底向上)

注:事件传递的过程 只跟文档树的结构有关系 跟界面显示的层叠效果没有任何关系

二、事件捕获和冒泡

(一)事件执行模式:

   a) 事件捕获时:父元素先触发,子元素后触发

  • 自上而下触发
  • 在addEventListener第三个参数设置为true时在捕捉的时候执行事件

   b) 事件冒泡时:子元素先触发,父元素后触发  W3C 标准默认是事件冒泡

  • 在onclick/attach和 addEventListener第三个参数设置为false时在冒泡的时候执行事件

   c)只能有一个阶段触发程序执行

   d)若事件经过所有元素都没有被执行处理,这个事件将消失

   e)整个事件处理过程,有个event事件对象在整个事件过程传播(W3C标准,ie8及其以下没有)

   f)阻止事件传递 唯一的方式就是阻止事件冒泡

小问答:

addEventListener的第三个参数为true是阻止事件传递还是false?

答:都不会阻止事件传递:因为true捕获阶段触发  false冒泡阶段触发

(二)阻止冒泡和系统默认事件

 1、阻止事件冒泡:

   event.stopPropagation() :W3C标准  不支持 ie9以下版本

   stopImmediatePropagation() :

  • 支持stopPropagation的浏览器中也可以用 
  • 不仅会阻止事件向父元素的冒泡  也会阻止同一个节点上同一事件的其他的事件处理程序(优先级比它低的或同元素同事件多处理程序时)

   event.cancelBubble=true: ie8及ie8以下可用

注:以上均阻止不了默认的系统事件

 2、阻止系统(浏览器)默认事件:

 默认事件——表单提交,a标签跳转,右键菜单等等

  event.preventDefault(): W3C标准  IE9以下不兼容

  return false: 以对象属性的方式注册的事件才生效  用addEventListener/attachEvent不生效

  event.returnValue=false:兼容IE

注:以上仅针对同一事件

不冒泡的事件:focus,blur,change,submit,reset,select等

(三)面试题

在一个 DOM 上同时绑定两个点击事件:一个用捕获,一个用冒泡。事件会执行几次,先执行冒泡还是捕获?

答案:

a) 该 DOM 上的事件如果被触发,会执行两次(执行次数等于绑定次数)

b) 如果该 DOM 是目标元素,则按事件绑定顺序执行,不区分冒泡/捕获

c) 如果该 DOM 是处于事件流中的非目标元素,则先执行捕获,后执行冒泡

三、事件代理

(一)概念:

  • 事件代理又称事件委托,是 JS 中常用绑定事件的常用技巧
  • 把原本需要绑定的事件代理给父元素,让父元素监听来事件,利用冒泡机制触发该事件
  • 利用事件的target属性和冒泡机制

(二)案例

   需求:1.点击按钮添加一个新的div内容为“new div5”

              2.点击每个div打印其内容

<style>
.box1{
  width: 200px;
  background-color:blueviolet;
}
.box2{
  height: 40px;
  line-height: 40px;
  background-color:pink;
  margin: 10px;
  text-align: center;
}
</style>
<div class="box1">
    <div class="box2">div1</div>
	<div class="box2">div2</div>
	<div class="box2">div3</div>
	<div class="box2">div4</div>
</div>
<button onclick="add()">点击添加一个div</button>
  •   不用事件代理实现需求的代码如下:
function add(){
    var box1=document.querySelector(".box1")
	var box2=document.createElement("div")
	box2.innerHTML="new div5"
	box2.className="box2"
	box1.appendChild(box2)			
}
var box2s=document.querySelectorAll(".box2")
box2s.forEach(el=>{
	el.addEventListener("click",function(e){  //给每一个div绑定点击事件
	     console.log(this.innerHTML)
	  })
})
/*这样设计的缺点
由于每次遍历都会绑定一次事件和生成新的函数来实现相同业务需求而导致性能消耗更高 
*/

  打印结果:

 

结果分析: 

点击添加的新的div没有触发点击事件 控制台打印不出该div的内容

所以静态的事件绑定在动态添加新元素后,新元素不能触发事件

  •  用事件代理实现需求的代码
var box1=document.querySelector(".box1")
box1.addEventListener("click",function(e){
		      console.log(e.target.innerHTML)
})	
/*给父元素绑定点事件 触发父元素的点击事件时 利用target定位到击到的具体的子元素 进而打印其内容	
 动态添加的new div5 也可以打印出内容
*/

  打印结果:

结果分析: 

点击添加的新的div触发了点击事件 控制台打印了该div的内容--new div5

仅绑定一个元素(父元素)就可以实现所有子元素的点击打印需求

  解决的问题:

  • 重复绑定相同的事件
  • 静态的事件绑定时动态添加元素进去后  添加进去的元素没有绑定的事件

(三)优缺点:

   优点:

  • 节省大量内存占用,降低性能的消耗 ,提升整体性能
  • 可以将事件应用于动态添加的子元素上,可以减少事件重复注册

   缺点:

  • 使用不当会造成事件在不应该触发时触发
  • 有些事件(没有冒泡特性的)不能用事件代理

适合用事件代理的事件:click、mousedown、mouseup、keyup、keydown、keypress等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈哈ha~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值