事件委托

2019-08-06  本文已影响0人  你喜欢吃青椒吗_c744

基本概念

事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素;

一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。

举个例子,比如一个宿舍的同学同时快递到了,一种方法就是他们都傻傻地一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一一分发给每个宿舍同学;

事件冒泡与捕获

image.png

为什么用事件委托

1:绑定事件越多,浏览器内存占用越大,严重影响性能。

2:ajax的出现,局部刷新的盛行,导致每次加载完,都要重新绑定事件

3:部分浏览器移除元素时,绑定的事件并没有被及时移除,导致的内存泄漏,严重影响性能

4:大部分ajax局部刷新的,只是显示的数据,而操作却是大部分相同的,重复绑定,会导致代码的耦合性过大,严重影响后期的维护。

事件委托影响性能的因素:

什么时候选择使用事件委托

1:只在必须的地方,使用事件委托,比如:ajax的局部刷新区域

2:尽量的减少绑定的层级,不在body元素上,进行绑定

3:减少绑定的次数,如果可以,那么把多个事件的绑定,合并到一次事件委托中去,由这个事件委托的回调,来进行分发。

一个例子

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<ul id="ul-test">
    <li>0</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
</ul>
</body>
<script type="text/javascript">
  var oUl=document.getElementById("ul-test");
  var oLi=oUl.getElementsByTagName("li");
  for(var i=0,len=oLi.length;i<len;i++){
    oLi[i].addEventListener("click",function(){
      alert(this.innerHTML)
    })
  }
</script>
</html>

问题在于:

解决的办法就是通过事件委托

var oUl=document.getElementById("ul-test");
oUl.addEventListener("click",function(ev){
  console.log(ev)
  var ev=ev||window.event;// 兼容性处理
  var target=ev.target||ev.srcElement;
   // 获取到目标阶段指向的元素。如果点击的最底层是li元素
  if(target.tagName.toLowerCase()==='li'){
    alert(target.innerHTML)
  }
})

原理

事件的传播有三个阶段:
当一个事件发生以后,它会在不同的DOM节点之间传播(propagation)。这种传播分成三个阶段:

这种三阶段的传播模型,会使得一个事件在多个节点上触发。比如,假设点击<div>之中嵌套一个<p>节点。

<div>
  <p>Click Me</p>
</div>

如果对这两个节点的click事件都设定监听函数,则click事件会被触发四次。

注意,用户点击网页的时候,浏览器总是假定click事件的目标节点,就是点击位置的嵌套最深的那个节点(嵌套在<div>节点的<p>节点)。所以,<p>节点的捕获阶段和冒泡阶段,都会显示为target阶段。

事件传播的最上层对象是window,接着依次是documenthtml(document.documentElement)body(document.body)。也就是说,如果<body>元素中有一个<div>元素,点击该元素。事件的传播顺序,在捕获阶段依次为window、document、html、body、div,在冒泡阶段依次为div、body、html、document、window。

定义

由于事件会在冒泡阶段传向父节点,因此可以把子节点的监听函数绑定在父节点上,用父节点的监听函数统一处理多个子节点的事件,这就是事件代理。

var ul = document.querySelector('ul');

ul.addEventListener('click', function(event) {
  if (event.target.tagName.toLowerCase() === 'li') {
    // some code
  }
});

上面这个函数事件监听绑在ul身上,但是监听到点击li的事件,然后处理li点击后的回调。

就算li是动态添加进来的依然能够监听到。

总结

由于一个事件在传播的过程中有三个阶段,由最外层的父节点一层层传递到最里面的子节点,先是捕获阶段,到目标阶段,再到冒泡阶段。如果我们想监听到动态添加的子节点的事件,我们可以把事件绑在父节点上,利用event.target,筛选到子节点,处理事件相应的回调!!!

参考文章

JavaScript 事件委托详解

深入理解-事件委托

事件委托(事件代理)

上一篇 下一篇

猜你喜欢

热点阅读