在 for 循环中分配点击处理程序

IT技术 javascript jquery jquery-selectors closures
2021-01-11 17:55:05

我有几个 div 的#mydiv1, #mydiv2, #mydiv3, ... 并且想为它们分配点击处理程序:

$(document).ready(function(){
  for(var i = 0; i < 20; i++) {
    $('#question' + i).click( function(){
      alert('you clicked ' + i);
    });
  }
});

但是,而不是'you clicked 3'在点击时显示#mydiv3(对于其他每一次点击),我得到'you clicked 20'. 我究竟做错了什么?

6个回答

在 Javascript 的循环创建闭包是一个常见的错误你需要有这样的回调函数:

function createCallback( i ){
  return function(){
    alert('you clicked' + i);
  }
}

$(document).ready(function(){
  for(var i = 0; i < 20; i++) {
    $('#question' + i).click( createCallback( i ) );
  }
});

2016 年 6 月 3 日更新:由于这个问题仍然受到一些关注,而且 ES6 也越来越流行,我建议采用现代解决方案。如果你写 ES6,你可以使用let关键字,它使i变量局部于循环而不是全局:

for(let i = 0; i < 20; i++) {
  $('#question' + i).click( function(){
    alert('you clicked ' + i);
  });
}

它更短,更容易理解。

真的不会称之为callback“回调”。这不是回调。它是一个用于创建回调的工厂
2021-03-18 17:55:05
实际上,作为解释,应该写下引用“i”的匿名函数仅在循环的上下文中执行,而不是立即运行。这意味着,当 onclick 事件发生时,“i”实际上处于循环的结束条件。您可以通过将“i”作为本地参数传递来规避此问题(正如此回调解决方案所做的那样)。
2021-03-24 17:55:05
非常有用的答案。也有这个问题,并且能够修改您的解决方案以在每次循环通过时创建一个绑定单击事件。
2021-04-01 17:55:05
它永远是二十。由客户端增量引起。
2021-04-09 17:55:05

澄清一下, i 等于 20 因为直到循环完成后才会触发点击事件。

$(document).ready(function(){
  for(var i = 0; i < 5; i++) {
   var $li= $('<li>' + i +'</li>');
      (function(i) {
           $li.click( function(){
           alert('you clicked ' + i);
         });
      }(i));
      $('#ul').append($li);
  }
});
通过匿名函数对我来说效果更好
2021-04-09 17:55:05

使用on附加“点击”处理程序,您可以使用事件数据来传递您的数据,例如:

for(var i = 0; i < 20; i++) {
  $('#question' + i).on('click', {'idx': i}, function(e) {
    alert('you clicked ' + e.data.idx);
  });
}

您可以通过分配一次点击处理程序(或至少不进行许多不必要的关闭)。将所有 div 放在一个 class 中mydivs,然后:

$(document).ready(function(){
    $('.mydivs').click(function(){
        // Get the number starting from the ID's 6th character
        // This assumes that the common prefix is "mydiv"
        var i = Number(this.id.slice(5));

        alert('you clicked ' + i);
    });
});

这会查看元素的 ID 以获取其编号,使用slicestring 方法去除首字母。

注意:使用可能更好

$('#divcontainer').on('click', '.mydivs', function(){

代替

$('.mydivs').click(function(){