js循環綁定事件


js循環綁定事件

在js中,用循環來為一個元素隊列的元素綁定事件,是一個常見的問題。

通常進入誤區的新人,都會理想當然地這么寫代碼:

(假設元素隊列為o,默認使用jQuery)

//error method
var o =$('.blockHead');
for(var i=0; i<o.length; i++){
	o[i].onclick = function(){
            alert(i);
	}
}

當然這種情況下,你會發現每個元素點擊運行時,顯示的 i值 都是 o.length-1;

因為js的函數是調用時觸發,綁定事件的時候i值並沒有被傳入執行函數里。

作為異步監聽的事件,點擊事件發生的時候,循環已經結束,此時的 i值 為[o.length-1], 觸發事件傳遞的參數自然是同一個最大值,而不是預期不同元素傳不同值。

 

解決辦法思路:將綁定事件過程中得到的i值,在執行函數域里保存起來;調用時自然就得到相應的結果。

方法一: 使用閉包函數存儲i值

var o = $('.blockHead');
for(var i=0; i<o.length; i++){
	o[i].onclick = (function closure(ii){
               //var ii;
               //we save ii in this scope
		return function(){
			alert(ii);
		}
	})(i);
}

 如上,colsure是一個閉包函數(closure函數名可省去,作匿名閉包函數),聲明后立即執行,傳遞了i值,於是在它的函數域里保存了i值(arguments參數列表里);

   函數的返回結果是事件處理函數,其參數ii就是colsure里保存的ii值,也就是循環時就傳遞的i值。

ps:方法一是非常常見的處理該問題的解決方法;在尋找解決方案的過程里,我發現了另一個寫法,如下。

 

方法二: 將事件綁定的代碼寫在一個外圍函數里 

var o = $('.blockHead');
for(var i=0; i<o.length; i++){
	attach(i,o[i]);
	function attach(ii,o){
		o.onclick = function(){
			alert(ii);
		};
	}
}

//或者 直接在聲明函數后立刻執行
var o = $('.blockHead');
for(var i=0; i<o.length; i++){
	(function attach(ii,o){
		o.onclick = function(){
			alert(ii);
		};
	})(i,o[i]);
}
//在函數域范圍內可訪問外層函數的變量,用一個生存與立即函數的變量來存貯i,於是可以寫成醬紫
var o = $('.blockHead');
for(var i=0; i<o.length; i++){
	(function (){
             var p = i;
             o[i].onclick = function(){
	        alert(p);
	  };
	})();
}

 

  同樣的道理,在attach的函數域里,onclick事件得到的ii值已經是執行循環便獲取的的i,而外部的i執行完循環后的結果是什么已經跟內部沒有關系了。

      稍許比方法一麻煩的是,參數需要多傳遞一個元素的引用。

      最后一個方法顯然是最簡便明朗的。

 

 js的事件代理機制

讓我們追溯到問題更深入的部分,即什么場景會出現[事件循環綁定]的要求?一個父級元素的子級元素隊列元素綁定事件,除了一個一個子級元素地去綁定有更好的解決方案么?

真巧,js有這么一種機制,叫 事件代理/委托(delegate),基於瀏覽器事件處理的冒泡機制,用一個事件處理程序可以管理某一類型的所有事件。

當需要多個元素添加事件的時候,可以通過將事件添加到它們的父節點而將事件委托給父節點來觸發處理函數。

使用代理的好處:減少事件處理程序的數量,能夠很好提高js性能;

                       延遲指定對DOM元素的處理程序,使得交互時間縮短。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM