事件委托在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. vue 引入 mint-ui 简单使用

    一 npm 方式 1,安装依赖 (已有项目) 如果想简单体验:基于vue-cli /* npm install vue -g npm install vue-cli   -g   // -g 是否全局 ...

  2. React组件的使用

     一.index.js 文件[基本配置] //react语法塘 import React from 'react'; //reactDom用来操作虚拟DOM import ReactDom from ...

  3. mysql 多主多从配置,自增id解决方案

    MySQL两主(多主)多从架构配置 一.角色划分 1.MySQL数据库规划 我现在的环境是:zhdy04和zhdy05已经做好了主主架构配置,现在需要的是把两台或者多台从服务器与主一一同步. 主机名 ...

  4. QK对中断的特殊处理

    1.QK的特性 QK(Quntum Kernel)是一个抢占式.基于优先级实时微内核.一个多任务调度器: QK不同于传统的RTOS,是非阻塞的,并且只用了一个stack: 对QK中的任务来说,采用了I ...

  5. python三大神器之装饰器

    装饰器的形成过程 假如你要写一个计算函数执行时间的函数,代码如下: import time def func1(): print('in func1') def timer(func): def in ...

  6. ruby 字符串加密

    str = 'This is a test.rb!' #DES加密 puts str.crypt('salt') #MD532位加密 require 'digest' puts Digest::MD5 ...

  7. Python 爬虫 招聘信息并存入数据库

    新学习了selenium,啪一下腾讯招聘 from lxml import etree from selenium import webdriver import pymysql def Geturl ...

  8. 路由追踪:traceroute/tcptraceroute

    一.工作原理 traceroute:IP路由过程中对数据包TTL(Time to Live,存活时间)进行处理.当路由器收到一个IP包时,会修改IP包的TTL(及由此造成的头部检验和checksum变 ...

  9. 北京Uber优步司机奖励政策(9月14日~9月20日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  10. [Jmeter]用Jmeter做压力测试(分布式)

    Jmeter 是Java应用,对于CPU和内存的消耗比较大,因此,当需要模拟数以千计的并发用户时,使用单台机器模拟所有的并发用户就有些力不从心,甚至会引起JAVA内存溢出错误.为了让jmeter工具提 ...