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)。
以上是JavaScript事件代理程式與如何使用代理實例用法詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!