资讯专栏INFORMATION COLUMN

好文推荐:javascript: 事件委托解析

Wuv1Up / 2768人阅读

摘要:前言之前不太明白事件委托。看了这个帖子,跟着代码操作了一遍,终于明白了事件委托。推荐理由一步一步,渐进式分析来说明事件委托。为签收快递,有两种办法一是三个人在公司门口等快递二是委托给前台代为签收。

前言:之前不太明白事件委托。 看了这个帖子,跟着代码操作了一遍,终于明白了事件委托。所以转载。
推荐理由:一步一步,渐进式分析来说明事件委托。

什么叫事件委托呢?它还有一个名字叫事件代理

JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

网上的各位大牛们讲事件委托基本上都用了同一个例子,就是取快递来解释这个现象,大家认真领会一下事件委托到底是一个什么原理:

有三个同事预计会在周一收到快递。为签收快递,有两种办法:一是三个人在公司门口等快递;二是委托给前台MM代为签收。现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。

这里其实还有2层意思的:

第一,现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的;

第二,新员工也是可以被前台MM代为签收的,即程序中新添加的dom节点也是有事件的。

为什么要用事件委托:

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

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

事件委托的原理:
事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。

事件委托怎么实现:

在介绍事件委托的方法之前,我们先来看一段一般方法的例子:

子节点实现相同的功能:

  • 111
  • 222
  • 333
  • 444
window.onload = function(){ 
    var oUl = document.getElementById("ul1"); 
    var aLi = oUl.getElementsByTagName("li"); 
    for(var i=0;i

上面的代码的意思很简单,相信很多人都是这么实现的,我们看看有多少次的dom操作,首先要找到ul,然后遍历li,然后点击li的时候,又要找一次目标的li的位置,才能执行最后的操作,每次点击都要找一次li;
那么我们用事件委托的方式做又会怎么样呢?

window.onload = function(){
    var oUl = document.getElementById("ul1");
   oUl.onclick = function(){
        alert(123);
    }
}

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

window.onload = function(){
  var oUl = document.getElementById("ul1");
  oUl.onclick = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == "li"){
            alert(123);
         alert(target.innerHTML);
    }
  }
}

上面的例子是说li操作的是同样的效果,要是每个li被点击的效果都不一样,那么用事件委托还有用吗?

window.onload = function(){
            var oBox = document.getElementById("box");
            oBox.onclick = function (ev) {
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLocaleLowerCase() == "input"){
                    switch(target.id){
                        case "add" :
                            alert("添加");
                            break;
                        case "remove" :
                            alert("删除");
                            break;
                        case "move" :
                            alert("移动");
                            break;
                        case "select" :
                            alert("选择");
                            break;
                    }
                }
            }

        }

现在讲的都是document加载完成的现有dom节点下的操作,那么如果是新增的节点的方法是什么?


    
  • 111
  • 222
  • 333
  • 444
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);
            };
        }

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

总结:
那什么样的事件可以用事件委托,什么样的事件不可以用呢?
适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。
值得注意的是,mouseover和mouseout虽然也有事件冒泡,但是处理它们的时候需要特别的注意,因为需要经常计算它们的位置,处理起来不太容易,另外如focus,blur之类的,本身就没用冒泡的特性,自然就不能用事件委托了。

作者: 熠熠生阳
链接:http://www.imooc.com/article/...
来源:慕课网

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89729.html

相关文章

  • [ 好文分享 ] jQuery最佳实践

    摘要:所以,最佳选择是。事实上,这种处理完全不必要。这样的设计,使得读取局部变量比读取全局变量快得多。请看下面两段代码,第一段代码是读取全局变量第二段代码是读取局部变量第二段代码读取变量的时候,不用前往上一层作用域,所以要比第一段代码快五六倍。 转自:http://www.ruanyifeng.com/blog/2011/08/jquery_best_practices.html ...

    mzlogin 评论0 收藏0
  • 新鲜出炉的8月前端面试题

    摘要:前言最近参加了几场面试,积累了一些高频面试题,我把面试题分为两类,一种是基础试题主要考察前端技基础是否扎实,是否能够将前端知识体系串联。 前言 最近参加了几场面试,积累了一些高频面试题,我把面试题分为两类,一种是基础试题: 主要考察前端技基础是否扎实,是否能够将前端知识体系串联。一种是开放式问题: 考察业务积累,是否有自己的思考,思考问题的方式,这类问题没有标准答案。 基础题 题目的答...

    qingshanli1988 评论0 收藏0
  • JavaScript 事件对内存和性能的影响

    摘要:事件对内存和性能的影响虽说事件处理程序可以为现代页面添加很强的交互能力,但是不分青红皂白就添加大量的事件处理程序绝对是一种愚蠢的行为。最适合采用事件委托的事件包括和。提交提交某个表单的操作代码移除事件处理程序提交中。。。 JavaScript 事件对内存和性能的影响 虽说事件处理程序可以为现代 Web 页面添加很强的交互能力,但是不分青红皂白就添加大量的事件处理程序绝对是一种愚蠢的行为...

    Ajian 评论0 收藏0
  • 简单说 JavaScript中的事件委托(下)

    摘要:说明上次我们说了一些,关于中事件委托的基础知识,这次我们继续来看。可选类型,一个选择器,用于指定哪些后代元素可以触发绑定的事件。类型,指定的事件处理函数。 说明 上次我们说了一些,关于 JavaScript中事件委托的 基础知识,这次我们继续来看。 解释 先来一段代码 1 2 ul.onclick...

    MasonEast 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<