什么是事件委托?
事件委托又称事件代理。就是利用事件冒泡,把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托就无法实现。
事件源:Event
对象提供了一个属性叫target
,可以返回事件的目标节点,标准浏览器用ev.target
,IE浏览器用event.srcElement
。
举个例子:快递员在等待签收快递的时候,一是可以在门口等快递送达;二是委托给公司前台代为签收。现实当中,我们大都采用委托的方案。前台收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台也会在收到寄给新员工的快递后核实并代为签收。
为什么要用事件委托?
在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率越大,100个li就要占用100个内存空间。如果要用事件委托,就会将所有的操作放到js程序里面,只对它的父级(如果只有一个父级)这一个对象进行操作,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;
事件委托的原理
事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。
比如,我们现在有一个无序列表,在无序列表里面有五个li,我们想要给每个li添加一个点击事件,这个时候,我们常规操作是通过循环给每个li添加点击事件。
普通代码:
<body>
<ul>
<li>111111</li>
<li>222222</li>
<li>333333</li>
<li>444444</li>
<li>555555</li>
</ul>
<script>
var li = document.querySelectorAll('li');
for(var i=0;i<li.length;i++){
li[i].onclick = function(e){
console.log(this)//指向 li,
console.log(e)//e.target=this => li,可以用this
this.style.color = 'red';
}
}
</script>
</body>
这种方法的确可以实现我们的点击操作,但是这个过程中,由于每次都要给li添加点击事件,造成访问DOM的次数过多,会延长整个页面的交互就绪时间。
所以,这里,我们就可以用到事件委托,即给ul注册点击事件,然后利用事件对象的 target
来找到当前点击的 li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器。
事件委托:
var ul = document.querySelector('ul');
ul.onclick = function(e){
console.log(this)//指向 ul
console.log(e)//e.target=this ,不可以用this
e.target.style.color = 'orange';
}
事件的三个阶段—–捕获、目标、冒泡
DOM2.0模型将事件处理流程分为三个阶段:1. 事件捕获阶段,2. 事件目标阶段,3. 事件冒泡阶段。
- 事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。
- 事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。
- 事件冒泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被触发。
事件委托的优点
使用事件委托对于web应用程序带来的几个优点:
- 减少内存空间的占用率,因为每一个函数都是一个对象,对象越多,内存占有率就越大,自然性能就越差,使用事件委托,只需要在其父元素中定义一个事件就可以;
- 可以方便地动态添加和修改元素,不需要因为元素的改动而修改事件绑定;
- 减少DOM操作的,减少浏览器的重绘(repaint)和重排(reflow),这样也就减少了因循环引用而带来的内存泄漏发生的概率,从而提高性能;
- 适合事件委托的事件有:click,mousedown,mouseup,keydown,keyup,keypress。