什么是事件委托?

概述

什么叫事件委托?

  • 事件委托就是利用事件冒泡,只指定一个事件处理程序,管理当前绑定下的所有元素的事件。
  • 也可以这么理解。比如一个宿舍的同学同时快递到了,一种方法就是他们一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一 一分发给每个宿舍同学;取快递就是一个事件,每个同学指的是需要响应事件的 DOM元素,而出去统一领取快递的宿舍长就是代理的元素,所以真正绑定事件的是这个元素,按照收件人分发快递的过程就是在事件执行中,需要判断当前响应的事件应该匹配到被代理元素中的哪一个或者哪几个。
  • 一个事件触发后,会在子元素和父元素之间传播。这种传播分成三个阶段。
    (1)捕获阶段:从window对象传导到目标节点(上层传到底层)称为“捕获阶段”,捕获阶段不会响应任何事件;
    (2)目标阶段:在目标节点上触发,称为“目标阶段”
    (3)冒泡阶段:从目标节点传导回window对象(从底层传回上层),称为“冒泡阶段”。事件代理即是利用事件冒泡的机制把里层所需要响应的事件绑定到外层。

事件委托的优点

  • 可以大量节省内存占用,减少事件注册

例子

给每个li执行点击事件

<ul id="ul1">
   <li a='1231dd' id="1" class="1.1">111</li>
   <li>222</li>
   <li>333</li>
   <li>444</li>
</ul>

传统方式

  1. 获取ul
  2. 通过获取到ul去获取下面的所有li
  3. 循环li的长度,依次去注册事件
window.onload = function () {
    var oUl = document.getElementById("ul1");
    var oLi = oUl.getElementsByTagName('li');
    for (let i = 0; i < oLi.length; i++) {
        oLi[i].onclick = function () {
            console.log(i, oLi[i]);
        }
    }
}

事件委托

  • 这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办,比如说只有点击li才会触发
  • Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较(习惯问题)。
oUl.onclick = function (ev) {
     var ev = ev || window.event
     var target = ev.target || ev.srcElement
     if (target.nodeName.toLowerCase() === 'li') {
         console.dir(target);
     }
     // console.log(target.nodeName.toLowerCase(), ev);
}
  • 加了个判断,只会nodeName===li才会有效果,不会影响其他。

动态增加节点

 <input type="button" name="" id="btn" value="添加" />
    <ul id="ul1">
        <li>111</li>
        <li>222</li>
        <li>333</li>
        <li>444</li>
    </ul>

传统方式

  • 移入li,li变红,移出li,li变白,这么一个效果,然后点击按钮,可以向ul中添加一个li子节点
window.onload = function () {
    var oBtn = document.getElementById("btn");
    var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    var num = 4;

    //鼠标移入变红,移出变白
    for (var i = 0; i < aLi.length; i++) {
        aLi[i].onmouseover = function () {
            this.style.background = 'red';
        };
        aLi[i].onmouseout = function () {
            this.style.background = '#fff';
        }
    }
    //添加新节点
    oBtn.onclick = function () {
        num++;
        var oLi = document.createElement('li');
        oLi.innerHTML = 111 * num;
        oUl.appendChild(oLi);
    };
}
  • 这是一般的做法,但是你会发现,新增的li是没有事件的,说明添加子节点的时候,事件没有一起添加进去,这不是我们想要的结果,那怎么做呢?一般的解决方案会是这样,将for循环用一个函数包起来,命名为initLi,如下:
window.onload = function(){
    var oBtn = document.getElementById("btn");
    var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    var num = 4;
    
    function initLi() {
        //鼠标移入变红,移出变白
        for(var i=0; i<aLi.length;i++){
            aLi[i].onmouseover = function(){
                this.style.background = 'red';
            };
            aLi[i].onmouseout = function(){
                this.style.background = '#fff';
            }
        }
    }
    initLi();
    //添加新节点
    oBtn.onclick = function(){
        num++;
        var oLi = document.createElement('li');
        oLi.innerHTML = 111*num;
        oUl.appendChild(oLi);
        initLi();
    };
}
  • 功能实现了。但是增加了一个dom操作,在性能方面跟事件委托存在一定的差异。

事件委托方式

  • 事件委托的方式,新添加的子元素是带有事件效果的,我们可以发现,当用事件委托的时候,根本就不需要去遍历元素的子节点,整体只注册一次ul事件,并没有给每个li都注册个监听。这样可以大大的减少dom操作,这就是事件委托的意义。
    window.onload = function () {
            var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul1");
            var aLi = oUl.getElementsByTagName('li');
            var num = 4;

            //事件委托,添加的子元素也有事件
            oUl.onmouseover = function (ev) {
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if (target.nodeName.toLowerCase() == 'li') {
                    target.style.background = "red";
                }
            };
            
            oUl.onmouseout = function (ev) {
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if (target.nodeName.toLowerCase() == 'li') {
                    target.style.background = "#fff";
                }
            };

            //添加新节点
            oBtn.onclick = function () {
                num++;
                var oLi = document.createElement('li');
                oLi.innerHTML = 111 * num;
                oUl.appendChild(oLi);
            };
        }
  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

代码の搬运工

记录学习,记录认知,记录。

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

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

打赏作者

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

抵扣说明:

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

余额充值