JavaScript中的事件代理/委托
事件委托在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中的事件代理/委托的更多相关文章
- 关于JavaScript中的事件代理
今天面试某家公司Web前端开发岗位,前面的问题回答的都还算凑活,并且又问了一下昨天面试时做的一道数组去重问题的解题思路(关于数组去重问题,可以观赏我前几天写的:http://www.cnblogs.c ...
- 关于JavaScript中的事件代理(例子:ul中无数的li上添加点击事件)
面试题:一个ul中有一千个li,如何给这一千个li绑定一个鼠标点击事件,当鼠标点击时alert出这个li的内容和li的位置坐标xy. 看到这个题目,我们一般首先想到的思路是,for循环,遍历1000次 ...
- js实例分析JavaScript中的事件委托和事件绑定
我们在学习JavaScript中,难免都会去网上查一些资料.也许偶尔就会遇到“事件委托”(也有的称我“事件代理”,这里不评论谁是谁非.以下全部称为“事件委托”),尤其是在查JavaScript的事件处 ...
- JavaScript中的事件委托机制跟深浅拷贝
今天聊下JavaScript中的事件委托跟深浅拷贝 事件委托 首先呢,介绍一下事件绑定 //方法一:通过onclick <button onclick="clickEvent()&qu ...
- 了解javascript中的事件(二)
本文目录如下: 零.寒暄 一.事件的分类 二.事件代理 2.1 问题引出 2.2 什么是事件代理 2.3 完整示例 二.事件代理 三.事件代理思想的用处 四.总结 零.寒暄 这篇博客本该出现在两个月以 ...
- javascript 中的事件机制
1.javascript中的事件. 事件流 javascript中的事件是以一种流的形式存在的. 一个事件会也有多个元素同时响应. 有时候这不是我们想要的效果, 我们只是需要某个特定的元素相应我们的绑 ...
- JavaScript中的事件对象
JavaScript中的事件对象 JavaScript中的事件对象是非常重要的,恐怕是我们在项目中使用的最多的了.在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含这所有与事件有 ...
- JavaScript 进阶教程一 JavaScript 中的事件流 - 事件冒泡和事件捕获
先看下面的示例代码: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Jav ...
- javascript中onclick事件能调用多个方法吗
Q: javascript中onclick事件能调用多个方法吗? A: 可以的,方法如下onclick="aa();bb();cc();"每个方法用“;”分号隔开就行了
随机推荐
- shutil.rmtree()
shutil.rmtree(path, ignore_errors=False, onerror=None) #递归地删除文件 def rmtree(path, ignore_errors=Fal ...
- Yii2之发送电子邮件
官方文档:http://www.yiiframework.com/doc-2.0/guide-tutorial-mailing.html 使用Yii2框架的时候,有时候需要发送电子邮件,Yiii2提供 ...
- Kafka 推荐网站
Kafka系列文章 [Kafka设计解析(一)- Kafka背景及架构介绍](http://www.jasongj.com/2015/03/10/KafkaColumn1/) [Kafka设计解析(二 ...
- HaoheDI让ETL变得简单
HaoheDI(昊合数据整合平台)http://www.haohedi.com,产品基于BS架构,开发运维均极为简单,可快速搭建ETL平台,广泛支持各种数据库.文本文件.SAP和Hadoop,开发数据 ...
- Linux3.5—视屏模块学习与分析
插入USB摄像头后,我看到了识别出的一些信息,在内核源码中搜到了相关信息: 搜索之后,在uvc_driver.c 帮助文档:linux-3.5/Documentation/video4linux/v4 ...
- web頁面優化以及SEO
轉載:https://blog.csdn.net/xustart7720/article/details/79960591 浏览器访问优化浏览器请求处理流程如下图: Etag:實體標籤.ETag是HT ...
- C语言经典程序100例
-------------------------------------------------------------------------------- [程序1] 题目:古典问题:有一对兔子 ...
- centos7关闭图形界面启动系统
手动敲那么多不累么?仅2条命令(好) 1,命令模式systemctl set-default multi-user.target 2,图形模式systemctl set-default graphic ...
- 【blockly教程】第三章Blockly顺序程序设计
3.1 什么是Blockly语言 2012年6月,Google发布了完全可视化的编程语言Google Blockly,整个界面清晰明了, 你可以如同在玩拼图一样用一块块图形对象构建出应用程序.每个图 ...
- python2.7入门---CGI编程&表单操作&cookie操作
看到标题我们首先有个疑问,什么是CGI?CGI 目前由NCSA维护,NCSA定义CGI为:CGI(Common Gateway Interface),通用网关接口,它是一段程序,运行在服务器上 ...