最近做的一个赛事系统里,有制作淘汰赛对阵图的需求,想来想去,变化太多,于是就偷了个懒,做了一个可以动态改变的表格,动态地增删行列,然后点击每一格进行设置……于是他们想怎么设置就不关我事了- -啊哈哈。
结果就是,在动态对表格插入一列后需要对整列的单元格添加点击onclick事件的时候,突然又想到这个问题,于是举个栗子发上来罢……怎么说,也是当时困扰过我的玩意……
HTML代码是这玩意
<!doctype html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
</head>
<body>
<ul id="test">
<li>aa</li>
<li>bb</li>
<li>cc</li>
<li>dd</li>
<li>ee</li>
<li>ff</li>
</ul>
<ul id="test_2">
<li>aaaaaaaaaaaaaaaaaaaa</li>
<li>bbbbbbbbbbbbbbbbbbbb</li>
<li>cccccccccccccccccccc</li>
<li>dddddddddddddddddddd</li>
<li>eeeeeeeeeeeeeeeeeeee</li>
<li>ffffffffffffffffffff</li>
</ul>
<a href="javascript:void(0);" mce_href="javascript:void(0);" onClick="add_event();">加载事件</a>
</body>
</html>
想在点击 加载事件 的按钮后,然后点击 test 框的每一行,弹出 test_2 对应行的内容。
想当然的,以前遇到这种问题的时候,脑袋里就会想到下面这段JS
function add_event(){
var lis = document.getElementById("test").getElementsByTagName("li");
var lis_2 = document.getElementById("test_2").getElementsByTagName("li");
for (var i=0; i<lis.length; i++){
lis[i].onclick = function(i){
window.alert(lis_2[i].innerHTML);
}
}
}
于是发生了啥,报错了 lis_2[i] is undefined
在知道了闭包这玩意后,于是开始用闭包试着去解决,虽然一开始没成功,像这样
function add_event(){
var lis = document.getElementById("test").getElementsByTagName("li");
var lis_2 = document.getElementById("test_2").getElementsByTagName("li");
for (var i=0; i<lis.length; i++){
(function(){
lis[i].onclick = function(){
window.alert(lis_2[i].innerHTML);
}
})();
}
}
还是报错了……错得一个鸟样……
最后改正一下……
变成这样
function add_event(){
var lis = document.getElementById("test").getElementsByTagName("li");
var lis_2 = document.getElementById("test_2").getElementsByTagName("li");
for (var i=0; i<lis.length; i++){
(function(){
var temp = i;
lis[i].onclick = function(){
window.alert(lis_2[temp].innerHTML);
}
})();
}
}
于是可以了- -
简单的原理解释:
onclick事件是在鼠标点击的时候才触发的,而在点击鼠标的时候,i 的值已经是被循环计算完了,一直都是循环结果的最终值。
(function(){ .. })(); 是一个立即执行的匿名函数,i 的每次循环,(function(){ .. })(); 里面的代码是立即生效的,var temp=i; 的作用是获取每次的外部变量 i 并将它保存至内部变量 temp 中,然后立即给对应的 li 绑定事件,这时的 temp 将是当前循环的 i 的值,而不是最终的 i 的值。