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

Posted

技术标签:

【中文标题】在 for 循环中分配点击处理程序【英文标题】:Assign click handlers in for loop 【发布时间】:2011-05-04 18:06:49 【问题描述】:

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

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

但是当点击#mydiv3(对于其他所有点击)我得到'you clicked 20',而不是显示'you clicked 3'。我做错了什么?

【问题讨论】:

【参考方案1】:

javascript 中创建 closures in loops 是一个常见错误。你需要有一些这样的回调函数:

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);
  );

它更短更容易理解。

【讨论】:

实际上作为解释应该写成引用“i”的匿名函数只在循环上下文中执行,而不是立即运行。这意味着,当 onclick 事件发生时,“i”实际上处于循环的结束条件。您可以通过将“i”作为本地参数传递来规避这个问题(就像这个回调解决方案所做的那样)。 真的不会打电话给callback“回调”。这不是回调。这是一个创建回调的工厂。 非常有用的答案。也有这个问题,并且能够修改您的解决方案以在每次循环通过时创建一个绑定点击事件。 永远是二十。由客户端增量引起。【参考方案2】:

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

【讨论】:

【参考方案3】:
$(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);
  
);

【讨论】:

通过匿名函数对我来说效果更好【参考方案4】:

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

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

//
// let's creat 20 buttons
//

for(var j = 0; j < 20; j++) 
	$('body').append($('<button/>', type: 'button', id: 'question' + j, text: 'Click Me ' + j))


//
// Passing data to the handler
//
for(var i = 0; i < 20; i++) 
  $('#question' + i).on('click', 'idx': i, function(e) 
    console.log('you clicked ' + e.data.idx);
  );
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

【参考方案5】:

您可以通过一次分配点击处理程序(或至少不进行许多不必要的关闭)来解决问题。把所有的div放在一个类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 以获取其编号,使用 slice string method 去除首字母。

注意:使用起来可能会更好

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

而不是

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

【讨论】:

【参考方案6】:

通常,如果您希望将点击句柄分配给大量项目,您需要一个容器(更高级别的 div)来为您解释点击,因为点击会从 dom 冒泡。

<div id="bucket">
    <span class="decorator-class" value="3">
    ...
</div>

<script>
   $(document).ready(function(e)
      $("#bucket").live('click', function()
         if(e.target).is('span')
            alert("elementid: " + $(e.target).val());
         
      
   
<script>

【讨论】:

以上是关于在 for 循环中分配点击处理程序的主要内容,如果未能解决你的问题,请参考以下文章

在for循环中分配代表的问题[重复]

在For循环中为点击功能分配JQuery

For/In 循环中的完成处理程序 - swift

微信小程序怎么给for循环的view点击时添加样式

为啥这个完成处理程序会跳过一个 for 循环

微信小程序,weixin,求助,一个循环列表,点击自身时增加一个样式