JavaScript事件代理
事件代理在JS世界中一个非常有用也很有趣的功能。当我们需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数。
这主要得益于浏览器的事件冒泡机制,下面我们具体举个例子来解释如何使用这个特性。
这个例子主要取自David Walsh的相关文章(How JavaScript Event Delegation Works)。
假设有一个 UL 的父节点,包含了很多个 Li 的子节点:
<ul id="list"> <li id="li-1">Li 1</li> <li id="li-2">Li 2</li> <li id="li-3">Li 3</li> <li id="li-4">Li 4</li> <li id="li-5">Li 5</li> </ul>
当我们的鼠标移到Li上的时候,需要获取此Li的相关信息并飘出悬浮窗以显示详细信息,或者当某个Li被点击的时候需要触发相应的处理事件。
我们通常的写法,是为每个Li都添加一些类似onMouseOver或者onClick之类的事件监听。
function addListenersLi(liElement) { liElement.onclick = function clickHandler() { //TODO }; liElement.onmouseover = function mouseOverHandler() { //TODO } } window.onload = function() { var ulElement = document.getElementById("list"); var liElements = ulElement.getElementByTagName("Li"); for (var i = liElements.length - 1; i >= 0; i--) { addListenersLi(liElements[i]); } }
如果这个UL中的Li子元素会频繁地添加或者删除,我们就需要在每次添加Li的时候都调用这个addListenersLi方法来为每个Li节点添加事件处理函数。
这会造成添加或者删除过程的复杂度和出错的可能性。
解决问题方法是使用事件代理机制,当事件被抛到更上层的父节点的时候,我们通过检查事件的目标对象(target)来判断并获取事件源Li。
下面的代码可以完成想要的效果:
/ 获取父节点,并为它添加一个click事件 document.getElementById("list").addEventListener("click",function(e) { // 检查事件源e.targe是否为Li if(e.target && e.target.nodeName.toUpperCase == "LI") { // //TODO console.log("List item ",e.target.id," was clicked!"); } });
为父节点添加一个click事件,当子节点被点击的时候,click事件会从子节点开始向上冒泡。父节点捕获到事件之后,通过判断e.target.nodeName来判断是否为我们需要处理的节点。并且通过e.target拿到了被点击的Li节点。从而可以获取到相应的信息,并作处理。
jQuery和Dojo中delegate函数
下面看一下Dojo和jQuery中提供的事件代理接口的使用方法。
jQuery:
$("#list").delegate("li", "click", function(){ // "$(this)" is the node that was clicked console.log("you clicked a link!",$(this)); });
jQuery的delegate的方法需要三个参数,一个选择器,一个时间名称,和事件处理函数。
而Dojo的与jQuery相似,仅是两者的编程风格上的差别:
require(["dojo/query","dojox/NodeList/delegate"], function(query,delegate){ query("#list").delegate("li","onclick",function(event) { // "this.node" is the node that was clicked console.log("you clicked a link!",this); }); })
Dojo的delegate模块在dojox.NodeList中,提供的接口与jQuery一样,参数也相同。
通过委托, 能够体会到使用事件委托对于开发带来的几个好处:
1.管理的函数变少了。不需要为每个元素都添加监听函数。对于同一个父节点下面类似的子元素,可以通过委托给父元素的监听函数来处理事件。
2.可以方便地动态添加和修改元素,不需要因为元素的改动而修改事件绑定。
3.JavaScript和DOM节点之间的关联变少了,这样也就减少了因循环引用而带来的内存泄漏发生的概率。
在JavaScript编程中使用代理
上面介绍的是对DOM事件处理时,利用浏览器冒泡机制为DOM元素添加事件代理。其实在纯JS编程中,我们也可以使用这样的编程模式,来创建代理对象来操作目标对象.
var delegate = function(client, clientMethod) { return function() { return clientMethod.apply(client, arguments); } } var Apple= function() { var _color = "red"; return { getColor: function() { console.log("Color: " + _color); }, setColor: function(color) { _color = color; } }; }; var a = new Apple(); var b = new Apple(); a.getColor(); a.setColor("green"); a.getColor(); //调用代理 var d = delegate(a, a.setColor); d("blue"); //执行代理 a.getColor(); //b.getColor();
上面的例子中,通过调用delegate()函数创建的代理函数d来操作对a的修改。
这种方式尽管是使用了apply(call也可以)来实现了调用对象的转移,但是从编程模式上实现了对某些对象的隐藏,可以保护这些对象不被随便访问和修改。
在很多框架中都引用了委托这个概念用来指定方法的运行作用域。
比较典型的如dojo.hitch(scope,method)和ExtJS的createDelegate(obj,args)。
Atas ialah kandungan terperinci JavaScript事件代理和如何使用代理实例用法详解. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!