注册

JavaScript中的事件委托

事件委托基本概念

事件委托,就是一个元素的响应事件的函数委托给另一个元素

一般我们都是把函数绑定给当前元素的父元素或更外层元素,当事件响应到需要绑定的元素的时候,会通过事件冒泡机制(或事件捕获)去触发外层元素的绑定事件,在外层元素上去执行函数

在了解事件委托之前,我们可以先了解事件流,事件冒泡以及事件捕获

事件流:捕获阶段,目标阶段,冒泡阶段

DOM事件流有3个阶段:捕获阶段,目标阶段,冒泡阶段;

三个阶段的顺序为:捕获阶段——目标阶段——冒泡阶段

事件冒泡

事件的触发响应会从最底层目标一层层地向外到最外层(根节点)

比如说我现在有一个盒子f,里面有个子元素s

  <div class="f">
       <div class="s"></div>
 </div>

添加事件

var f = document.querySelector('.f')
var s = document.querySelector('.s')
f.addEventListener('click',()=>{
   console.log('fffff');
})
s.addEventListener('click',()=>{
   console.log('sssss');
})

当我点击子元素的时候

af36c4c83ffa4b41be7a37c80706c24f~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

冒泡顺序 s -> f

事件捕获

事件响应从最外层的Window开始,逐级向内层前进,直到具体事件目标元素。在捕获阶段,不会处理响应元素注册的冒泡事件

继续使用上一个例子,只需要将addEventListener第三个参数改为true即可

添加事件

var f = document.querySelector('.f')
var s = document.querySelector('.s')
f.addEventListener('click',()=>{
   console.log('fffff');
},true)
s.addEventListener('click',()=>{
   console.log('sssss');
},true)

点击子元素

14b88238407f466d8daa70708b2ccca4~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp? 捕获顺序 f -> s

这里我们可以思考一下,如果同时绑定了冒泡和捕获事件的话,会有怎样的执行顺序呢?

例子不变,稍微改一下js代码

var f = document.querySelector('.f')
var s = document.querySelector('.s')
f.addEventListener('click',()=>{
   console.log('f捕获');
},true)
s.addEventListener('click',()=>{
   console.log('s捕获');
},true)
f.addEventListener('click',()=>{
   console.log('f冒泡');
})
s.addEventListener('click',()=>{
   console.log('s冒泡');
})

此时点击子元素

35dc289f9d83450aa36988e6ef1b534e~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp? 执行顺序: f捕获->s捕获->s冒泡—>f冒泡

得出结论:当我们同时绑定捕获和冒泡事件的时候,会先从外层开始捕获到目标元素,然后由目标元素冒泡到外层

回到事件委托

了解了事件捕获和事件冒泡,再来看事件委托就很好理解了

强调一遍,事件委托把函数绑定给当前元素的父元素或更外层元素,当事件响应到需要绑定的元素的时候,会通过事件冒泡机制(或事件捕获)去触发外层元素的绑定事件,在外层元素上去执行函数

新开一个例子

<ul class="list">
       <li class="item"></li>
       <li class="item"></li>
       <li class="item"></li>
       <li class="item"></li>
       <li class="item"></li>
</ul>

现在我们有一个列表,当我们点击列表中的某一项时可以触发对应事件,如果我们给列表的每一项都添加事件,对于内存消耗是非常大的,效率上需要消耗很多性能

这个时候我们就可以把这个点击事件绑定到他的父层,也就是 ul 上,然后在执行事件的时候再去匹配判断目标元素;

var list = document.querySelector('.list')
// 利用冒泡机制实现
list.addEventListener('click',(e)=>{
  e.target.style.backgroundColor='blue'
})
// 利用捕获机制实现
list.addEventListener('click',(e)=>{
  e.target.style.backgroundColor='red'
},true)

当我点击其中一个子元素的时候

97b0c942de1641e092677e428ad43dfd~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

总结

  • 事件委托就是根据事件冒泡或事件捕获的机制来实现的

  • 事件冒泡就是事件的触发响应会从最底层目标一层层地向外到最外层(根节点)

  • 事件捕获就是事件响应从最外层的Window开始,逐级向内层前进,直到具体事件目标元素。在捕获阶段,不会处理响应元素注册的冒泡事件

补充:

对于目标元素,捕获和冒泡的执行顺序是由绑定事件的执行顺序决定的

作者:张宏都
来源:https://juejin.cn/post/7100468737647575048

0 个评论

要回复文章请先登录注册