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的事件冒泡机制来实现,有兴趣的可以研究一下。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章