事件委托在JS高级程序设计中的定义为“利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件”

如何理解上面的这句话呢,在网上,大牛们一般都使用收快递这个例子来解释的,那我也来谈谈收快递

一个公司有三个人要取快递,一种方法是三个人都到楼下去等快递,另一种方法是让前台的MM代收快递,并且可以按照不同收件人的要求签收,一般实际中都是使用后者,因为后者还有一个优势就是,不管公司来了多少新员工,前台MM也能收到新员工的快递核实后代为签收。

那么为什么要用事件委托呢?有两个原因:

1、在JS程序中,添加到网页上的事件处理程序的数量将直接影响到网页的整体运行性能,因为需要不断与DOM节点进行交互,访问DOM节点的次数越多,引起浏览器重绘与重排的次数就越多,但是如果使用事件委托的话,只需要将所有操作放在JS程序中,与DOM节点只需要交互一次,大大提高了性能。

2、在JS中,每一个函数都是一个对象,所以创建的函数数量越多,占的内存空间也就越多,而事件委托就能大大减少函数的数量,从而减少对内存空间的占用。

再来说说事件委托的原理吧

事件委托其实就是运用事件冒泡的原理,给最外层的祖先节点绑定一个事件处理程序,当点击这个祖先节点里面的每一个后代节点,都会按照冒泡的原理,往上冒泡,直到触发到祖先节点的事件处理程序,就会触发相应的事件。

那么如何实现事件委托呢,先来看一下一个简单的例子,点击每一个li元素,都会输出123,我们一般的做法是如下

var oUl = document.getElementById("ul");
var oLis = document.getElementsByTagName("li");
for(var i=0;i<oLis.length;i++){
oLis[i].onclick = function(){
alert("123");
}
}

以上程序相当于给每一个li节点都添加了一个点击事件的处理程序,相当于执行相同的操作,但是却要依次访问每一个节点,这样访问DOM节点的次数就很多了,那么用事件委托是如何实现的呢?看看下面的代码

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

只需要给父节点ul添加一个点击事件,里面所有的li节点都会通过冒泡原理,触发到ul节点里面的事件处理程序,这样大大减少了DOM节点的操作,提高了网页的性能。

那么大家可能会问,如果我只想触发当前我点击的这个节点的事件要如何实现呢,JS里面的EVENT对象提供了一个属性叫做target,可以返回事件的目标节点,我们称为事件源,也就是说target可以理解为当前操作的节点,但不是真正操作这个节点,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较。

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

这个时候只有点击li元素才会触发事件处理程序了。

那么问题又来了,如果每一个li元素的事件处理程序都不一样呢,那么能用事件委托实现?先来看一下一般我们是如何实现的

<div id="box">
<input type="button" id="add" value="添加" />
<input type="button" id="remove" value="删除" />
<input type="button" id="move" value="移动" />
<input type="button" id="select" value="选择" />
</div>
window.onload = function(){
var Add = document.getElementById("add");
var Remove = document.getElementById("remove");
var Move = document.getElementById("move");
var Select = document.getElementById("select"); Add.onclick = function(){
alert('添加');
};
Remove.onclick = function(){
alert('删除');
};
Move.onclick = function(){
alert('移动');
};
Select.onclick = function(){
alert('选择');
} }

那如果用事件委托是如何实现的

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;
}
}
} }

用事件代理就可以做到只操作一次DOM节点,就能完成所有效果。

上面讲的都是文档加载完之后的事件处理,那么如果我们新添加了一个li元素呢,还可以有事件吗?我做了一个实验

<input type="button" name="" id="btn" value="添加" />
<ul id="ul1">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
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节点并没有事件可以触发,但是我们一般的解决方法是将事件处理函数封装在一个函数里面,每创建一个新节点都调用一次这个函数,代码如下

window.onload = function(){
var oBtn = document.getElementById("btn");
var oUl = document.getElementById("ul1");
var aLi = oUl.getElementsByTagName('li');
var num = 4; function mHover () {
//鼠标移入变红,移出变白
for(var i=0; i<aLi.length;i++){
aLi[i].onmouseover = function(){
this.style.background = 'red';
};
aLi[i].onmouseout = function(){
this.style.background = '#fff';
}
}
}
mHover ();
//添加新节点
oBtn.onclick = function(){
num++;
var oLi = document.createElement('li');
oLi.innerHTML = 111*num;
oUl.appendChild(oLi);
mHover ();
};
}

上面的代码已经解决了新添加元素也有事件的问题,但是问题又有了,这个方法大大的增加了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);
};
}

JavaScript中的事件代理/委托的更多相关文章

  1. 关于JavaScript中的事件代理

    今天面试某家公司Web前端开发岗位,前面的问题回答的都还算凑活,并且又问了一下昨天面试时做的一道数组去重问题的解题思路(关于数组去重问题,可以观赏我前几天写的:http://www.cnblogs.c ...

  2. 关于JavaScript中的事件代理(例子:ul中无数的li上添加点击事件)

    面试题:一个ul中有一千个li,如何给这一千个li绑定一个鼠标点击事件,当鼠标点击时alert出这个li的内容和li的位置坐标xy. 看到这个题目,我们一般首先想到的思路是,for循环,遍历1000次 ...

  3. js实例分析JavaScript中的事件委托和事件绑定

    我们在学习JavaScript中,难免都会去网上查一些资料.也许偶尔就会遇到“事件委托”(也有的称我“事件代理”,这里不评论谁是谁非.以下全部称为“事件委托”),尤其是在查JavaScript的事件处 ...

  4. JavaScript中的事件委托机制跟深浅拷贝

    今天聊下JavaScript中的事件委托跟深浅拷贝 事件委托 首先呢,介绍一下事件绑定 //方法一:通过onclick <button onclick="clickEvent()&qu ...

  5. 了解javascript中的事件(二)

    本文目录如下: 零.寒暄 一.事件的分类 二.事件代理 2.1 问题引出 2.2 什么是事件代理 2.3 完整示例 二.事件代理 三.事件代理思想的用处 四.总结 零.寒暄 这篇博客本该出现在两个月以 ...

  6. javascript 中的事件机制

    1.javascript中的事件. 事件流 javascript中的事件是以一种流的形式存在的. 一个事件会也有多个元素同时响应. 有时候这不是我们想要的效果, 我们只是需要某个特定的元素相应我们的绑 ...

  7. JavaScript中的事件对象

    JavaScript中的事件对象 JavaScript中的事件对象是非常重要的,恐怕是我们在项目中使用的最多的了.在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含这所有与事件有 ...

  8. JavaScript 进阶教程一 JavaScript 中的事件流 - 事件冒泡和事件捕获

    先看下面的示例代码: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Jav ...

  9. javascript中onclick事件能调用多个方法吗

    Q: javascript中onclick事件能调用多个方法吗? A: 可以的,方法如下onclick="aa();bb();cc();"每个方法用“;”分号隔开就行了

随机推荐

  1. Java并发编程:浅析几种线程安全模型 [转]

    多线程编程一直是老生常谈的问题,在Java中,随着JDK的逐渐发展,JDK提供给我们的并发模型也越来越多,本文摘取三例使用不同原理的模型,分析其大致原理.目录如下: 1.COW之CopyOnWrite ...

  2. PHP Fatal error: Call to undefined function think\finfo_open()

    PHP Fatal error:  Call to undefined function think\finfo_open() php.ini      extension=php_fileinfo. ...

  3. 分享一个hybrid框架ionic

    ionic 是一个 HTML5 应用程序开发框架. 可以使用 HTML.CSS 和 Javascript 构建接近原生体验的移动应用程序.具有速度快,界面现代化.美观等特点.下面一起看一下如何使用 安 ...

  4. 浅谈CSS高度坍塌

    高度坍塌情况: 当父元素没有设置高度,且子元素块都向左(右)浮动起来,那么父元素就会出现坍塌的现象. 解决办法: 在父元素包含块中加一个div: 优点:兼容性强,适合初学者. 缺点:不利于优化. 方法 ...

  5. 本人擅长Ai、Fw、Fl、Br、Ae、Pr、Id、Ps等

    本人擅长Ai.Fw.Fl.Br.Ae.Pr.Id.Ps等软件的安装与卸载,精通CSS.JavaScript.PHP.ASP.C.C++.C#.Java.Ruby.Perl.Lisp.python.Ob ...

  6. Asp.Net Core使用Log4Net优化日志【项目开源】

    我在前一篇文章中介绍了一种使用Log4Net的方法,但是那种方法打出来的日志不是很直观 然后我前不久阅读了一篇非常不错的博客:https://www.cnblogs.com/guolianyu/p/9 ...

  7. PHP使用阿里大鱼发送短信验证

    目前,基本上所有的网站注册都要求手机绑定,并通过下发短信验证码方式验证手机的真实性,提高了用户的真实性.但是一般企业单独申请短信行业通道都比较困难,因此选择一家信誉好,稳定性.及时性强的第三方短信通道 ...

  8. 大数据学习--day02(标识符、变量、数据类型、类型转换、进制转换、原码反码补码)

    标识符.变量.数据类型.类型转换.进制转换.原码反码补码 标识符: java50个关键字不能做标识符,以数字开头不能做标识符(这个老是忘记写一个类名的时候) 变量: 变量分为成员变量和局部变量,注意作 ...

  9. 嵌入式GPIO接口及操作(二)

    目标:C语言实现点亮LED灯 首先是main函数,并不特殊,它是被系统调用来执行的,main函数结束后要返回调用main函数的地址处,那么裸机程序,没有操作系统做这些工作,就要自己写调用main函数的 ...

  10. MAVLink功能开发,移植教程。

    MAVLink功能开发 -----------------本文由"智御电子"提供,同时提供视频移植教程,以便电子爱好者交流学习.---------------- 1.MAVLink ...