【问题标题】:Onclick adds to last element in loop only [duplicate]Onclick 仅添加到循环中的最后一个元素[重复]
【发布时间】:2012-09-29 07:57:14
【问题描述】:

可能重复:
Assign click handlers in for loop

我的代码中的循环需要帮助。

我遍历一个数组并添加对 div 的点击。但它总是将 onclicks 添加到循环的最后一个循环,并有效地取消之前的循环。

所以我有这个作为我的循环:

    start = 0;

for(i = start; i < (start+8); i++){ //8 per page
    if(i == array.length){ 
        break;  //page end
    } else {
        (function(i){
             document.getElementById('cell'+i).onclick = function(){ select(i); }
        })(i);  
    }
}

这里发生的是 div id cell7 添加了点击,但 div id cell0cell6 没有。我猜这与i 在循环中发生变化的事实有关,因此函数中的i 也会受到影响?

我该如何解决这个问题?

【问题讨论】:

  • 我不使用 jquery 或任何库,因此指向 jquery 的解决方案并不是很有用。
  • @Dave:这是你的实际代码吗?您正在关闭 i 变量,因此每次迭代都会创建一个单独的范围,该范围具有自己的 i 与外部循环的 i 分开。
  • 是的,这是我的代码 - 我没有关注 closing over the i?
  • @user1689607 嗯,没错。
  • @Dave 立即调用的函数使用自己的i 变量创建一个新的变量范围。在该函数调用中创建的处理程序关闭本地 i 变量,并保留对它的引用。基本上,您已经用内部 i 遮盖了外部 i,因此您的处理程序将引用该 i 并正常工作。

标签: javascript


【解决方案1】:

你已经接近了:

(function(i){
    document.getElementById('cell' + i).onclick = function(){ select(i); }
})(i); 

我想你想要的是:

document.getElementById('cell'+i).onclick = (function(i){
    return function(){ select(i); }
})(i); 

另外,因为你有:

for(i = start; i < (start+8); i++)

i 没有被声明,所以它变成了全局的。声明 'i' 使其保持本地化(假设这是函数代码):

for (var i = start; i < (start+8); i++)

如果它是全局代码,它不会有任何区别(但无论如何都要声明它)。

编辑

以上内容并不能解决您的问题,它只是改变了语法。

以下“工作”对我来说,cell0 到 cell7 得到一个监听器,其余的没有。 select 显示正确的值(0 到 7,具体取决于单击的值)。

<script>
    function addListener() {
      var start = 0;
      for(i = start; i < (start+8); i++){ 
        document.getElementById('cell'+i).onclick = (function(i){
            return function(){ select(i); }
        })(i);  
      }
    }
    function select(arg) {
      alert(arg);
    }
    window.onload = addListener;
</script>

<p id="cell0">0</p>
<p id="cell1">1</p>
<p id="cell2">2</p>
<p id="cell3">3</p>
<p id="cell4">4</p>
<p id="cell5">5</p>
<p id="cell6">6</p>
<p id="cell7">7</p>
<p id="cell8">8</p>
<p id="cell9">9</p>

【讨论】:

  • 还是同样的问题 =/ 它只分配给最后一个 div 其余的不做任何事情。
  • 当我把它简化成这样:document.getElementById('cell'+i).onclick = select(i); 它确实按照它应该的方式运行,除了函数直接运行(显然),但是使用上面的方法你建议只让它在最后一个 div 上工作循环。
  • 有些东西你没有显示,可能与if(i == array.length)有关。我发布的示例“作品”。
【解决方案2】:

试试这个example。 var i = 1 假设您的 HTMLElement id 从 1 开始。更改以反映情况。

var select = function(i) {
    console.log(i);
};

var arr = ["1", "2", 3, 4, 5, 6];

var start = 0;
var max = 8;

for (var i=1; i<(start + max); i++) {
    if (i === arr.length) {
        break;
    } else {
        (function(i) {
            var element = document.getElementById(['cell', i].join(''));
            element.onclick = function() {
                 select(i);  
            };
        })(i);
    }
}

​ 然而,调用外部函数应该是一个更快的实现。

【讨论】:

  • 似乎对我有用。只是好奇:为什么使用['cell', i].join('') 而不是'cell' + i?最近看到的越来越多了。
  • 我做了很多 node.js,在一些研究过程中,我偶然发现了这个 Google writeup。从那以后我一直在使用它,现在它已成为我的惯例。
【解决方案3】:

我不知道为什么,但这些建议并没有解决我的问题 - 但我设法通过在循环期间显示 div 时添加到 onclicks 来解决它,所以我最终这样做了:

innerHTML = '<Div onclick="">'; //etc etc

与其将 div 添加到输出“然后”稍后分配 onclick... 不知道我的新方法是否是最佳选择,但它有效,所以我必须坚持下去!

【讨论】:

  • 你和其他所有人的演示都对我有用。你用的是IE6还是什么的?顺便说一句,标签名称应该总是小写,即:&lt;div onclick=""&gt;
  • 感谢小写@MiniGod 的提示
猜你喜欢
  • 2013-12-15
  • 1970-01-01
  • 2016-02-22
  • 2021-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-02
  • 2019-10-22
相关资源
最近更新 更多