JS事件委托

2019-03-15 admin

事件委托(又名事件代理),就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

网上有关于事件委托的一个“取快递”例子,十分生动,这里我对它作一些修改和拓展,然后通过程序来说明事件委托的机制。

某公司有三位员工,他们的快递收件地址为公司,每当有快递送达时,快递员拨打其电话进行通知,他们接到电话后去取件。

员工ID 员工名称 联系方式
A 111111
B 222222
C 333333

对应到页面,就是每个员工是一个标记:

<ul id="前台工作人员">
    <li id="A">员工甲</li>
    <li id="B">员工乙</li>
    <li id="C">员工丙</li>
</ul>

每位员工接电话取快递的行为就是一个个事件,这里我们假设收取快递行为对应着onclick事件:


A.onclik = function() {
    收取快递;
};
B.onclick = function() {
    收取快递;
};
C.onclick = function() {
    收取快递;
};

以上的实现,通常为通过循环遍历每一个员工,为其增加事件:

/*程序1*/
var aUl = document.getElemengtByID("前台工作人员");
var aLi = aUl.getElemengtsByTagName("li");
for (var i = 0; i < aLi.length; i++) {
    aLi[i].onclick = function() {
        收取快递;
    }
}

可以看到,为每个员工都设置一个事件,会产生冗余代码,占用内存,同时会进行多次DOM操作(与DOM节点进行交互),影响页面运行性能。

“减少DOM操作是性能优化的主要思想之一”

于是,我们理所当然地想到:为什么不能让前台工作人员帮我们签收快递呢?

<ul id="前台工作人员">
    <li id="A">员工甲</li>
    <li id="B">员工乙</li>
    <li id="C">员工丙</li>
</ul>

/*程序2*/
var tel = document.getElementById("前台工作人员");
tel.onclick = function() {
    收取快递;
}

假设此时快递员打电话通知员工甲取件(onclick),但员工甲的DOM节点<li>并无对应事件(onclick),所以这个事件会“冒泡”到<li>的父元素<ul>,发现<ul>上有_onclick_处理事件,于是触发该事件,由前台工作人员收取快递。

可以看到,这样一来,不仅缩减代码量,同时与DOM节点的交互次数也得到了缩减。

还有一个优点:当增加新的DOM节点时,自动携带父元素的事件效果。也就是说,当有一个新员工丁来公司后,前台工作人员会直接帮他收取快递,而无需专门为他设置事件。

例如,当新员工丁来到公司后:

...
<input type="button" id="btn" value="添加新员工">
...

...
/*程序3*/
var aBtn = document.getElementById("btn");
aBtn.onclick = function() {
    var aLi = document.createElement("li");
    oLi.innerHTML = "员工丁";
    aUl.appendChild(aLi);
}
...

在不使用事件委托的程序中,新增的员工丁是没有事件的,我们需要用一个函数包含住程序1:

/*程序4*/
function pro1() {
    var aUl = document.getElemengtByID("前台工作人员");
    var aLi = aUl.getElemengtsByTagName("li");
    for (var i = 0; i < aLi.length; i++) {
        aLi[i].onclick = function() {
            收取快递;
        }
    }
}

然后在新增新员工丁的程序的末尾执行这个函数:

/*程序5*/
var aBtn = document.getElementById("btn");
aBtn.onclick = function() {
    ...
    pro1();
}

这样做的缺点是显而易见的:DOM节点交互次数成倍增加。 若我们采用事件委托机制来实现,就不会存在这个问题,子元素节点的onclick事件会直接在父元素节点得到执行。


到这里,我们会想到:对于同一种事件来说,使用事件委托将其放置在父元素节点上固然很方便。但如果对于不同的子元素节点要执行不同的事件呢,还能使用事件委托吗?

答案是肯定的。

例如上述三位公司员工,总是使用固定品牌的快递:

  • 员工甲因为便宜,喜欢使用申通快递,申通只送到园区大门;
  • 员工乙是京东会员,总是购买京东自营商品,京东快递送到楼下;
  • 员工丙是顺丰VIP,顺丰快递会送到送到所在楼层大厅。

他们三位在接到电话后,前台工作人员需要去不同的地方取件,对于不使用事件委托的程序,需要对每个人设置独特的处理事件:

var A = document.getElementById("A");
var B = document.getElementById("B");
var C = document.getElementById("C");

A.onclick = function() {
    去园区大门取快递;
}
B.onclick = function() {
    去楼下取快递;
}
C.onclick = function() {
    去本层大厅取快递;
}

至少需要三次DOM操作,而且为每一个对应节点都设置了事件函数。

而若采用事件委托:


var aUl = document.getElemengtByID("前台工作人员");
aUl.onclick = function (ev) {
    var target = ev || window.event; /*兼容浏览器*/
    var target = ev.target || ev.srcElement; /*兼容浏览器*/
    if (target.nodeName.toLocaleLowerCase() == "li") {
        switch(target.id) {
            case "A" :
                去园区大门取快递;
                break;
            case "B" :
                去楼下取快递;
                break;
            case "C" :
                去本层大厅取快递;
                break;
        }
    }
}

这样一来,DOM操作就只有一次,其他的操作都在JS内进行,可以有效提升网页性能。

以上便是JS事件委托的基本思想。简而言之,就是利用事件冒泡这一特点,来对事件进行管理,减少冗余代码,减少不必要的创建,减少交互操作以节约内存和提高性能。

事件冒泡

事件冒泡是当触发某个DOM元素节点时,若该节点没有对应事件,则检查其父元素是否有对应事件,若有,则执行,若没有,继续向上检查。与其对应的还有事件捕获。

关于事件流的具体分析,将在以后的文章中总结。

[转载]原文链接:https://segmentfault.com/a/1190000018513639

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-57742.html

文章标题:JS事件委托

相关文章
从2014年的发展来展望JS的未来将会如何
&lt;font face=&quot;寰�杞�闆呴粦, Arial, sans-serif &quot;&gt;2014骞达紝杞�浠惰�屼笟鍙戝睍杩呴€燂紝鍚勭�嶈��瑷€灞傚嚭涓嶇┓锛屼互婊¤冻鐢ㄦ埛涓嶆柇鍙樺寲鐨勯渶姹傘€傝繖浜涜��...
2015-11-12
three.js实现围绕某物体旋转
话不多说,请看代码: 可以拖动右上角观察变化 &lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot; style=&quot;width: 100%; height:100%;&quot;&gt...
2017-02-17
JavaScript教程:JS中的原型
Keith Peters 几年前发表的一篇博文,关于学习没有“new”的世界,其中解释了使用原型继承代替构造函数。两者都是纯粹的原型编码。 标准方法(The Standard Way) 一直以来,我们学习的在 JavaScript 里创建对...
2015-11-12
NodeJS参考手册pdf版
下载地址:Nodejs参考手册PDF版下载 ...
2015-11-12
jsdom 中文文档(纯翻译)
jsdom是一个纯粹由 javascript 实现的一系列 web标准,特别是 WHATWG 组织制定的DOM和 HTML 标准,用于在 nodejs 中使用。大体上来说,该项目的目标是模拟足够的Web浏览器子集,以便用于测试和挖掘真实世界...
2018-05-14
Node.js学习(1)----HTTP服务器与客户端
Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端。http.Server 是一个基于事件的 HTTP 服务器,它的核心由 Node.js 下层 C++部分实现,而接口由 Jav...
2015-11-12
Riot.js:不足1KB的MVP客户端框架
Riot.js是一款MVP(模型-视图-呈现)开源客户端框架,其最大的特点就是体积非常小,不足1KB,虽然体积小,但它可以帮助用户构建大规模的Web应用程序。 Riot.js是由Moot公司开发,目前最新版本为v0.9.2,遵循MIT开源许...
2016-03-11
使用jspdf生成pdf报表
由于前台html已经动态生成报表,而且,前台有一个功能,一个date range组件,当你拖动的时候,报表会在不提交到后台的情况下动态变化。 因此需要用到js生成生报表: 用到的组件: jquery.js jspdf.js canvg.js...
2017-03-25
javaScript+turn.js实现图书翻页效果实例代码
为了实现图书翻页的效果我们在网上可以看到很多教程 在这里推荐turn.js 网上的turn.js 有api 不过是英文的  很多人看起来不方便 .关于代码也是奇形怪状在这里我将详细讲解如何使用turn.js实现翻页效果 ,本篇文章只是讲解 ...
2017-03-16
JavaScript 事件流、事件处理程序及事件对象总结
JS与HTML之间的交互通过事件实现。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用监听器(或处理程序)来预定事件,以便事件发生时执行相应的代码。这种在传统软件工程中被称为观察员模式,支持页面的行为与页面的外观之间的松散耦合。...
2017-04-05
回到顶部