如果你想给网页添加点JavaScript的交互性,也许你已经听过JavaScript的事件代理(event delegation),并且觉得这是那些发烧友级别的JavaScript程序员才会关心的什么费解的设计模式之一。事实上,如果你已经知道怎么添加JavaScript的事件处理器(event handler),实现事件代理也是件轻而易举的事情。

JavaScript事件是所有网页互动性的根基(我指的是真正的互动性,而不仅是那些CSS下拉菜单)。在传统的事件处理中,你按照需要为每一个元素添加或者是删除事件处理器。然而,事件处理器将有可能导致内存泄露或者是性能下降——你用得越多这种风险就越大。JavaScript事件代理则是一种简单的技巧,通过它你可以把事件处理器添加到一个父级元素上,这样就避免了把事件处理器添加到多个子级元素上。

它是怎么运作的呢?

事件代理用到了两个在JavaSciprt事件中常被忽略的特性:事件冒泡以及目标元素。当一个元素上的事件被触发的时候,比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有祖先元素中被触发。这一过程被称为事件冒泡;这个事件从原始元素开始一直冒泡到DOM树的最上层。任何一个事件的目标元素都是最开始的那个元素,在我们的这个例子中也就是按钮,并且它在我们的元素对象中以属性的形式出现。使用事件代理,我们可以把事件处理器添加到一个元素上,等待一个事件从它的子级元素里冒泡上来,并且可以得知这个事件是从哪个元素开始的。

这对我有什么好处呢?
      想象一下现在我们有一个10列、100行的HTML表格,你希望在用户点击表格中的某一单元格的时候做点什么。比如说我有一次就需要让表格中的每一个单元格在被点击的时候变成可编辑状态。如果把事件处理器加到这1000个单元格会产生一个很大的性能问题,并且有可能导致内存泄露甚至是浏览器的崩溃。相反地,使用事件代理,你只需要把一个事件处理器添加到table元素上就可以了,这个函数可以把点击事件给截下来,并且判断出是哪个单元格被点击了。

用代码写出来是什么样呢?

代码很简单,我们所要关心的只是如何检测目标元素而已。比方说我们有一个table元素,ID是“report”,我们为这个表格添加一个事件处理器以调用editCell函数。editCell函数需要判断传到table来的事件的目标元素。考虑到我们要写的几个函数中都有可能用到这一功能,所以我们把它单独放到一个名为getEventTarget的函数中:

function getEventTarget(e) {
e = e || window.event;
return e.target || e.srcElement;
}

e这个变量表示的是一个事件对象,我们只需要写一点点跨浏览器的代码来返回目标元素,在IE里目标元素放在srcElemnt属性中,而在其它浏览器里则是target属性。

接下来就是editCell函数了,这个函数调用到了getEventTarget函数。一旦我们得到了目标元素,剩下的事情就是看看它是否是我们所需要的那个元素了。

function editCell(e) 

{
var target = getEventTarget(e);
if(target.tagName.toLowerCase() =='td') {
// DO SOMETHING WITH THE CELL
}
}

在editCell函数中,我们通过检查目标元素标签名称的方法来确定它是否是一个表格的单元格。这种检查也许过于简单了点;如果它是这个目标元素单元格里的另一个元素呢?我们需要为代码做一点小小的修改以便于其找出父级的td元素。如果说有些单元格不需要被编辑怎么办呢?此种情况下我们可以为那些不可编辑的单元格添加一个指定的样式名称,然后在把单元格变成可编辑状态之前先检查它是否不包含那个样式名称。选择总是多样化的,你只需找到适合你应用程序的那一种。

有哪些优点和缺点呢?

JavaScript事件代理带来的好处有:

那些需要创建的以及驻留在内存中的事件处理器少了。这是很重要的一点,这样我们就提高了性能,并降低了崩溃的风险。 
在DOM更新后无须重新绑定事件处理器了。如果你的页面是动态生成的,比如说通过Ajax,你不再需要在元素被载入或者卸载的时候来添加或者删除事件处理器了。 
潜在的问题也许并不那么明显,但是一旦你注意到这些问题,你就可以轻松地避免它们:

你的事件管理代码有成为性能瓶颈的风险,所以尽量使它能够短小精悍。

不是所有的事件都能冒泡的。blur、focus、load和unload不能像其它事件一样冒泡。事实上blur和focus可以用事件捕获而非事件冒泡的方法获得(在IE之外的其它浏览器中)。
在管理鼠标事件的时候有些需要注意的地方。如果你的代码处理mousemove事件的话你遇上性能瓶颈的风险可就大了,因为mousemove事件触发非常频繁。而mouseout则因为其怪异的表现而变得很难用事件代理来管理。

总结:
      已经有一些使用主流类库的事件代理示例出现了,比如说jQuery、Prototype以及Yahoo! UI。你也可以找到那些不用任何类库的例子,比如说Usable Type blog上的这一个。一旦需要的话,事件代理将是你工具箱里的一件得心应手的工具,而且它很容易实现。

事件代理总结: 已经有一些使用主流类库的事件代理示例出现了,比如说jQuery、Prototype以及Yahoo! UI。你也可以找到那些不用任何类库的例子,比如说Usable Type blog上的这一个。一旦需要的话,事件代理将是你工具箱里的一件得心应手的工具,而且它很容易实现。的更多相关文章

  1. one(type,[data],fn) 为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数。

    one(type,[data],fn) 概述 为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数. 在每个对象上,这个事件处理函数只会被执行一次.其他规则与bind()函数相同.这 ...

  2. on(events,[selector],[data],fn) 在选择元素上绑定一个或多个事件的事件处理函数

    on(events,[selector],[data],fn) 概述 在选择元素上绑定一个或多个事件的事件处理函数.大理石平台精度等级 on()方法绑定事件处理程序到当前选定的jQuery对象中的元素 ...

  3. 如何维护一个1000 IP的免费代理池

    楔子 好友李博士要买房了, 前几天应邀帮他抓链家的数据分析下房价, 爬到一半遇到了验证码. 李博士的想法是每天把链家在售的二手房数据都抓一遍, 然后按照时间序列分析. 链家线上在交易的二手房数据大概有 ...

  4. 设计模式 - 动态代理原理及模仿JDK Proxy 写一个属于自己的动态代理

    本篇文章代码内容较多,讲的可能会有些粗糙,大家可以选择性阅读. 本篇文章的目的是简单的分析动态代理的原理及模仿JDK Proxy手写一个动态代理以及对几种代理做一个总结. 对于代理模式的介绍和讲解,网 ...

  5. off(events,[selector],[fn]) 在选择元素上移除一个或多个事件的事件处理函数。

    off(events,[selector],[fn]) 概述 在选择元素上移除一个或多个事件的事件处理函数. off() 方法移除用.on()绑定的事件处理程序.有关详细信息,请参阅该网页上deleg ...

  6. 实现一个简单的基于动态代理的 AOP

    实现一个简单的基于动态代理的 AOP Intro 上次看基于动态代理的 AOP 框架实现,立了一个 Flag, 自己写一个简单的 AOP 实现示例,今天过来填坑了 目前的实现是基于 Emit 来做的, ...

  7. UEditor百度编辑器,工具栏上自定义添加一个普通按钮

    添加一个名叫“hougelou”的普通按钮在工具栏上: 第一步:找到ueditor.config.js文件中的toolbars数组,增加一个“hougelou”字符串,然后找到labelMap数组,对 ...

  8. C# 调用一个按钮的Click事件(利用反射)

    最基本的调用方法 (1)button1.PerformClick();(2)button1_Click(null,null);(3)button_Click(null,new EventArgs()) ...

  9. 【云计算】K8S DaemonSet 每个node上都运行一个pod

    Kubernetes容器集群中的日志系统集成实践 Kubernetes是原生的容器编排管理系统,对于负载均衡.服务发现.高可用.滚动升级.自动伸缩等容器云平台的功能要求有原生支持.今天我分享一下我们在 ...

随机推荐

  1. arp欺骗进行流量截获-2

    上一篇讲了原理,那么这一篇主要讲如何实现.基本上也就是实现上面的两个步骤,这里基于gopacket实现,我会带着大家一步步详细把每个步骤都讲到. ARP 欺骗 首先就是伪造ARP请求,让A和B把数据包 ...

  2. kali linux之防火墙识别

    通过检查回包,可能识别端口是否经过防火墙过滤,设备多种多样,结果存在一定的误差 Send Response   Type SYN   NO    Filtered(先发送syn 如果不给回复 防火墙可 ...

  3. php代码审计8审计文件上传漏洞

    文件上传漏洞是指用户上传了一个可执行的脚步文件,并通过此脚本文件获得了执行服务器端命令的能力,这种攻击方式是最直接和有效的,文件上传本身是没问题的,有问题的是文件上传后,服务器怎么处理,解释文件,通过 ...

  4. 题解 CF948A 【Protect Sheep】

    题目链接 额..这道题亮点在: $you$ $do$ $not$ $need$ $to$ $minimize$ $their$ $number.$ 所以说嘛... 直接判断狼的四周有没有紧挨着的羊,没 ...

  5. Windows下Python第三方.whl的安装

    1.改成.zip 2.解压 3.然后把解压出来的文件放到C:\Python27\Lib\site-packages下即可.

  6. IPython&Jupyter私房手册

    Jupyter是以Ipython为基础,可以极大的方便开发,对于如何使用,网上的资料都不太全.因此决定自己编写一个私房手册方便随时查找. 1. 安装和配置 安装不多说,不想折腾直接安装anaconda ...

  7. [APIO2009]抢掠计划 tarjan缩点+spfa BZOJ1179

    题目描述 Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设 ...

  8. ionic4 添加自定义字体图标

    在angular.json中的style中引入css文件: 然后在variables.scss中添加内容:

  9. [Microsoft] 微软技术平台的Cloud Building平台AppVeyor

    Link: http://www.tuicool.com/articles/uMBZba http://www.appveyor.com/ 随着云技术的不断完善,基于云的应用越发丰富起来.AppVey ...

  10. tornado 11 异步编程

    tornado 11 异步编程 一.同步与异步 同步 #含义:指两个或两个以上随时间变化的量在变化过程中保持一定的相对关系 #现象:有一个共同的时钟,按来的顺序一个一个处理 #直观感受:需要等待,效率 ...