JQuery Mobile 開發學習手記(一):JS批量設置按鈕動作的問題

本博客已棄用,更新版本請訪問 www.dss886.com

剛剛接觸JavaScript,用的是JQuery Mobile框架,很多東西還不熟悉,寫的代碼難免會想當然得用寫Java和Android時的慣性思維。


今天遇到一個問題,我動態生成了若干個按鈕,id命名爲“Comment_1”、“Comment_2”……在設置按鈕監聽的時候,由於按鈕總數是無法事先知道的,所以不可能爲每一個按鈕寫一個監聽,於是我用了循環來重複設置監聽,代碼如下:

for(i = 0; i < commentNum; i++){
	$('a#Comment_'+i).click(function(){
		sessionStorage.curComment = comments[i].cid;
		$.mobile.changePage("commentInfo.html");
	});
}

然而,在測試代碼的時候發現,第3行一直報錯:Uncaught TypeError: Cannot read property 'cid' of undefined,即comments[i]未定義。在中間加了一個log輸出i,發現點擊任何一個按鈕,i的值都是commentNum。

這種寫法在Java和Android裏是正確的,但是爲什麼在JS裏不對了呢?百度了一下,大致明白了一點點。

在Java中,UI的界面事件(比如按鈕按下、觸摸、滑動)是由虛擬機進行監聽的,監聽到了點擊動作,就一層一層向下傳遞,直到被按鈕接收到,然後進行處理。在Java/Android中這個監聽是需要提前向虛擬機進行“註冊”的,下面是Android中典型的循環設置監聽的代碼:

Button[] buttons = {btn1,btn2,btn3,btn4,btn5};
	for(int i = 0; i < buttons.length; i++){
		buttons[i].setOnClickListener(new OnClickListener(){
		@Override
		public void onClick(View v) {
			//do something
		}
	});
}

這段代碼在UI界面生成完畢前運行,for循環每循環一次,buttons數組中就有一個按鈕都被設置了監聽,直到全部設置完畢。UI界面生成完畢後,用戶點擊每個按鈕就會觸發對應的動作。

然而,與Java不同,JavaScript並沒有類似的監聽機制,而使用的是看上去很類似的“事件綁定”機制。當一個按鈕被按下的時候,click()內的代碼纔會被執行,而一般用戶按下按鈕的時候,js內的代碼都已經執行完畢了,For循環也早已經循環完畢,這個時候i的值爲CommentNum,執行comments[i]就會報錯——i超過了數組下標範圍。

那麼怎麼才能給這些按鈕設置監聽/綁定呢?如果我們仍然要用For循環進行綁定的話,可以使用以下代碼:

for(i = 0; i < commentNum; i++){
	(function(){
		var index = i;
		$('a#Comment_'+index).click(function(){
			sessionStorage.curComment = comments[i].cid;
			$.mobile.changePage("commentInfo.html");
		});
	 })();
 }

這裏利用了JS的閉包原理,每次循環都會新建一個閉包,裏面的變量值(在這裏是index的值)在運行完畢後並不會被銷燬,而是一直保存(參考:JS閉包的作用原理),當你按下按鈕時,click()被觸發,這個時候index就是其對於的id號了。


PS:其實並不推薦這樣使用循環綁定事件,過多的閉包會影響性能,最好是用js的事件冒泡機制來實現,有興趣的可以研究一下。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章