javascript事件代理
在编程中,如果我们不想或不能够直接操纵目标对象,我们可以利用delegate创建一个代理对象来调用目标对象的方法,从而达到操纵目标对象的目的。毋庸置疑,代理对象要拥有目标对象的引用。我们来看一下javascript的一个最简单实现:
var delegate = function (client,clientMethod ){ return function () { return clientMethod.apply(client,arguments); } } var agentMethod = delegate(client, client.method ) agentMethod(); |
或者我们改变一下第二个参数,传个字符串进去:
var delegate = function (client,clientMethod ){ return function () { return client[clientMethod].apply(client,arguments); } } /****************略*******************/ var d = delegate(a, "setColor" ); |
我们还可以搞一些很好玩的东西,下面的例子取自一个日本博客。
由于delegate实现目标对象的隐藏,这对于我们保护一些核心对象是非常有用的。不过,说实在javascript的delegate基本算是call与apply的傀儡,因为js中只有这2个方法提供了改变当前函数内部this作用域的功能。不过,要实现对类的委托而不是实例的委托,这就复杂得多。Prototype.js,YUI与JQuery都有相应的实现。具体自己可去参考它们的源码。接着下来,我将讲述delegate在事件上的应用,这可是个无以伦比的东东,就是改变侦听器的位置(改变事件的绑定对象)。或者说,它得益于javascript独特的事件传播机制,因此实现起来非常容易,大家要好好运行它,我以前也在富文本编辑器中用过。
$.addEvent(colorPicker, 'click' , function (){ var e = arguments[0] || window.event, td = e.srcElement ? e.srcElement : e.target, nn = td.nodeName.toLowerCase(); if (nn == 'td' ){ var cmd = colorPicker.getAttribute( "title" ); var val = td.bgColor; _format(cmd,val); e.cancelBubble = true ; colorPicker.style.display = 'none' ; } }); |
上面就是我在富文本编辑器撷取前景色与背景色的代码,注意,我是把事件绑定在颜色面板上,而不是面板上的那一个个格子上。为了直观起见,便于大家操作,我改用下面这个例子:
< ul id="nav"> < li >< a href="http://www.cnblogs.com/">博客园</ a ></ li > < li >< a href="http://www.blueidea.com/">蓝色理想</ a ></ li > < li >< a href="http://www.51js.com/html/bbs.html">无忧脚本</ a ></ li > < li >< a href="http://www.javaeye.com/">javaeye</ a ></ li > < li >< a href="http://community.csdn.net/">CSDN</ a ></ li > </ ul > |
现在我们要点击列表中链接,取出里面的内容,传统的方法,我们需要遍历添加所有a元素:
window.onload = function (){ var nav = document.getElementById( "nav" ); var links = nav.getElementsByTagName( "a" ); for ( var i=0,l = links.length; i<l; i++) { links[i].onclick = function () { alert( this .innerHTML); return false ; } } } |
新的方法,用nav代理了它下面所有元素,让它负责大家的onclick事件,包括它自己的,也不管是否为a元素,所以有时我们需要做一些判断,但少了遍历DOM树,效率明显提高。
window.onload = function (){ var nav = document.getElementById( "nav" ); nav.onclick = function () { var e = arguments[0] || window.event, target = e.srcElement ? e.srcElement : e.target; alert(target.innerHTML); return false ; } } |
为什么它会行得通呢?!因为DOM2.0的事件模型是这样的,如果某个元素触发一个事件,如onclick,顶层对象document就会发出一个事件流,随着DOM树往目标元素流去,这就是传说中的捕获阶段,也就是原Netscape的事件执行模式,沿途的元素如果绑定了事件,它是不会执行的!第二阶段,就是到达了目标元素,执行它上面的绑定事件,但如果onclick只是个空实现,当然是没有效果啦!第三阶级,就是起泡阶级,原IE的事件执行模式,从目标元素往顶层元素折回,如果沿途有onclick事件,就随个触发!因此我们是点击了a元素,但它的onclick事件为空,当事件流上浮到ul元素时,发现ul元素绑定了onclick事件,就执行当中的函数。如果ul的祖先元素也绑定了onclick事件呢?!继续执行!有多少执行多少!看下面的例子:
正由于这个特性,我们就可以利用ul的onclick去代理它下面所有元素的onclick事件。原来,我们需要给这些a元素准备五个侦听器(EventListener),现在我们只需要1个,节省了4个,如果这个列表有一百行呢?就节省了99个!在商务应用,我们经过会遇到许多报表(grid,实质是用table做的),我们需要为每行添加悬浮变色效果与点击编辑功能,这就用到onmouseover 、 onmouseout 与 onclick事件,如果这个报表有五千行,我们也只需要三个侦听器,节省了14997个!如果用传统方法做这个grid,IE6这样垃圾的游览器不卡到你吐血。因此,善用event delegation会大大提高我们程序的性能。好了,文章到此为止,再见。
附上一些有用的链接:
http://blog.xole.net/article.php?id=632
http://htmlblog.net/bubble-menu-javascript-or-playing-with-yuis-event-delegation/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义