JS中的事件委托

概述

事件委托也叫事件代理
首先理解一下事件冒泡:事件的触发响应会从最底层目标一层层地向外到最外层(根节点)。
事件代理即是利用事件冒泡机制把里层所需要的响应事件绑定到外层。

For example

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

在这里,取快递就是一个事件,每个同学指的是需要响应事件的 DOM 元素,而出去统一领取快递的宿舍长就是代理的元素,所以真正绑定事件的是这个元素,按照收件人分发快递的过程就是在事件执行中,需要判断当前响应的事件应该匹配到被代理元素中的哪一个或者哪几个。

代码实例

假定我们有一个ul元素,它有几个子元素:

<ul id="parent-list">
    <li id="post-1">Item 1</li>
    <li id="post-2">Item 2</li>
    <li id="post-3">Item 3</li>
    <li id="post-4">Item 4</li>
    <li id="post-5">Item 5</li>
    <li id="post-6">Item 6</li>
</ul>

当点击子元素li时,事件会冒泡到父ul元素,这时可以检查事件对象的target属性,捕获真正被点击的节点元素的引用。

document.getElementById("parent-list").addEventListener("click",function(e){
    //e.target是被点击的元素
    if(e.target && e.target.nodeName == 'LI'){
        console.log('list item',e.target.id,'was clicked')
    }
})

第一步是给父元素添加事件监听器。当有事件触发监听器时,检查事件的来源,排除非li子元素事件。如果是一个li元素,我们就找到了目标,如果不是一个li元素,事件将被忽略。

事件委托的优点

<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>
// ...... 代表中间还有未知数个 li
减少内存消耗

一般来说DOM需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的dom需要添加事件处理呢?比如我们有100个li,每个li都有相同的click事件,可能我们会用for循环的方法来遍历所有的li,然后给它添加事件,那这么做会存在什么影响呢?

在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少dom操作的原因;如果要用到事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;

每个函数都是一个对象,是对象就会占用内存,对象越多内存占用率就越大,自然性能就越差,比如100个li就要占用100个内存空间,如果1000个、10000个或者更多呢。。。如果用事件委托,那么我们就可以只对它的父级这一个对象进行操作了,这样我们就需要一个内存空间就够了,省了很多内存占用,自然性能就会更好。
所以,事件委托可以减少大量的内存消耗,节约效率。

动态绑定事件

添加元素的页面代码:

<input type="button" id="add" value="Add" name="">
<ul id="parent-list">
    <li>1111</li>
    <li>2222</li>
    <li>3333</li>
</ul>

正常的js代码:

var oUl = document.getElementById('parent-list')
var addBtn = document.getElementById('add')
var oLi = document.getElementsByTagName('li')
var num = 3
for (var i = 0; i < oLi.length; i++) {
    oLi[i].onclick = function(e){
        console.log(e.target.innerHTML)
    }
}
//后来新增的li元素是没有这个点击事件的,在添加子节点的时候事件并没有一起添加进去,当然这里通过改进也是可以给新元素添加点击事件,但无疑又增加了些dom操作。
addBtn.onclick = function(){
    num ++ 
    var oLi = document.createElement("li")
    oLi.innerHTML = 1111*num
    oUl.appendChild(oLi)
}

事件委托实现的方法:

var oUl = document.getElementById('parent-list')
var addBtn = document.getElementById('add')
var num = 3
oUl.addEventListener("click",function(e){
    //e.target是被点击的元素
    if(e.target && e.target.nodeName == 'LI'){
        console.log(e.target.innerHTML)
    }
})
//用事件委托的方式,新添加的元素是直接带有事件效果的
addBtn.onclick = function(){
    num ++ 
    var oLi = document.createElement("li")
    oLi.innerHTML = 1111*num
    oUl.appendChild(oLi)
}

当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在js里面的执行,这样可以大大的减少dom操作,这才是事件委托的精髓所在。

JQuery中的事件委托

$.on

基本用法:

$('.parent').on('click','a',function(){
    console.log('click enent on tag a')
})

它是.parent元素之下的a元素的事件代理到$(‘.parent’)之上,只要在这个元素上有点击事件,就会自动寻找到.parent元素下的a元素,然后响应事件;

$.live

基本用法:

$('a','.parent').live('click',function(){
    console.log('click enent on tag a')
})

同上,然而如果没有传入父层元素 (.parent) (document)上;(已废除)


总结

哪些事件适合用委托呢?
click,mousedown,mouseup,keydown,keyup,keypress。
需要注意的点是mouseover和mouseout,mousemove也是有冒泡事件的,但是处理起来需要特别注意,由于需要经常计算它们的位置,处理起来不太容易。
focus、blur等本身就没有冒泡事件,自然就不能用事件委托了。

参考网站
http://www.cnblogs.com/liugang-vip/p/5616484.html
https://zhuanlan.zhihu.com/p/26536815
http://www.webhek.com/post/event-delegate.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值