`

JavaScript的事件代理比你想的要简单

 
阅读更多

如果你想要给你的网页添加点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里目标元素放在srcElemtn属性中,而在其它浏览器里则是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上的这一个。

一旦需要的话,事件代理将是你工具箱里的一件得心应手的工具,而且它很容易实现。

分享到:
评论

相关推荐

    proximitter:为利用 JavaScript 代理而构建的简单事件库

    为利用 JavaScript 而构建的简单事件库 快速开始 // automatically add "init" handler events . oninit = ( ) => { console . log ( "init1" ) ; } ; // same as events . on ( "init" , ( ) => { console . log...

    深入分析Javascript事件代理

    要搞清楚什么是事件代理,就需要先搞清楚什么是代理。 从商业角度来讲,代理就是:我有货,你没货,但丫我没时间、没精力全部卖掉,而你一天闲的蛋疼,只剩下时间了。于是,我委托你帮我买,然后哥给你提成。这个...

    JavaScript设计模式之代理模式简单实例教程

    本文实例讲述了JavaScript设计模式之代理模式。分享给大家供大家参考,具体如下: 一、代理模式概念 代理,顾名思义就是帮助别人做事,GoF对代理模式的定义如下: 代理模式(Proxy),为其他对象提供一种代理以控制...

    javascript事件模型代码

    本节稍稍深入地讨论关于事件处理的话题,如果你对模式、闭包和面向对象等概念还不太理解,不妨暂且等阅读完相关内容之后再回过头来阅读它,相信你会有很大收获。 1 事件处理模式 在程序设计领域,“事件处理”是一...

    JavaScript设计模式之缓存代理模式原理与简单用法示例

    本文实例讲述了JavaScript设计模式之缓存代理模式原理与简单用法。分享给大家供大家参考,具体如下: 一、原理: 缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前的一致...

    JavaScript王者归来part.1 总数2

     13.5.1 事件处理模式--一个实现简单事件处理模式的例子   13.5.2 用户事件接口的定义   13.5.3 事件代理和事件注册--一个实现标准事件接口的例子   13.5.4 标准模式--事件分派和接收   13.6 一个例子--...

    使用JavaScript和MQTT实现的一个简单的物联网应用

    该Demo是一个使用JavaScript和MQTT协议实现的物联网应用示例,展示了一个完整的物联网系统的基本架构和流程。该应用包含四个主要部分:客户端(Client)、代理服务器(Broker)、服务端(Server)和应用端(App)。 客户端...

    [JavaScript.DOM高级程序设计](加)桑贝斯.扫描版.part1.rar

     1.2.6 一定要自己动手写代码   1.3 JavaScript语法中常见的陷阱   1.3.1 区分大小写   1.3.2 单引号与双引号   1.3.3 换行   1.3.4 可选的分号和花括号   1.3.5 重载(并非真正的重载)   ...

    一个代理库,它提供了简单的钩子来一致地操纵 http 和 https 流量_JavaScript_代码_相关文件_下载

    filternet 实现了一个功能丰富的代理服务器,它允许编码人员以一致的方式拦截和操作请求和响应。... 标准 HTTP 代理 ...最简单的例子,一切都在闪烁! 更多详情、使用方法,请下载后阅读README.md文件

    浅析javascript中的事件代理

    题目本身很简单:一个ul中有一千个li,如何给这一千个li绑定一个鼠标点击事件,当鼠标点击时alert出这个li的内容和li的位置坐标xy, <li id=li1>1 <li id=li2>2 <li id=li3>3 ... <li id=li1000>1000 需要...

    JavaScript实现添加及删除事件的方法小结

    JavaScript添加、删除事件的方法,也就是让某些方法生效指定次数,可以是一次、两次或更多次,但指定次数执行完毕后就删除该方法,使其失效,如果你经常从事JS编程,你就会知道这种功能用得比较多。 先来看看一个...

    Glype在线代理程序 1.4.6.zip

    Glype在线代理程序是一个用PHP编写的基于Web的代理脚本,用来作为web的代理服务器,可帮你请求目标URL,并生成相应的页面,无需修改浏览器配置即可访问各种网站。 主要特点: 即插即用,无需安装 基于Web的管理...

    JavaScript设计模式之代理模式

    我们来举一个简单的例子,假如dudu要送酸奶小妹玫瑰花,却不知道她的联系方式或者不好意思,想委托大叔去送这些玫瑰,那大叔就是个代理(其实挺好的,可以扣几朵给媳妇),那我们如何来做呢?调用方式就非常简单了:1....

    [JavaScript.DOM高级程序设计](加)桑贝斯.扫描版.part3.rar

     1.2.6 一定要自己动手写代码   1.3 JavaScript语法中常见的陷阱   1.3.1 区分大小写   1.3.2 单引号与双引号   1.3.3 换行   1.3.4 可选的分号和花括号   1.3.5 重载(并非真正的重载)   ...

    JS-son:轻量级JavaScript推理循环代理库

    JS-son-精简,可扩展JavaScript代理编程库 JS-son是一个精简且可扩展JavaScript库,用于编程代理。 它着重于推理循环(代理内部),并支持信念-愿望-意图方法等。 通过以下方式安装: npm install js-son-agent信念-...

    [JavaScript.DOM高级程序设计](加)桑贝斯.扫描版.part2.rar

     1.2.6 一定要自己动手写代码   1.3 JavaScript语法中常见的陷阱   1.3.1 区分大小写   1.3.2 单引号与双引号   1.3.3 换行   1.3.4 可选的分号和花括号   1.3.5 重载(并非真正的重载)   ...

    任何使用 HTML、CSS 和 JavaScript 的 URL 下载器以及源代码

    JavaScript的:下载器的功能由JavaScript提供支持,允许动态处理用户输入和文件获取。 如何使用: 粘贴 URL:复制要下载的文件的 URL。 输入 URL:打开“任何文件 URL 下载器”,将文件 URL 粘贴到提供的输入字段...

    neo4j-driver:简单的 javascript neo4j 驱动程序

    如果 Neo4j 位于反向代理之后,则调查潜在问题(即在发现期间更改主机名/端口) 为事务端点响应提供流支持 允许更改 resultDataContents -> 应该是选项对象的一部分 提供日志钩子 提供诸如(即将到期的事务、事务已...

    Javascript AJAX跨域Flash辅助插件Ajaxf.zip

    Javascript跨域传输数据存在很大的限制,通过普通的方式很难突破这个限制,通常使用API来跨域,更经常看到的是通过页面代理的方式访问,这样实现起来很繁琐,效率也很低,所以也就搞出了这个插件,通过Flash来实现...

Global site tag (gtag.js) - Google Analytics