web-dev-qa-db-ja.com

forループでクリックハンドラーを割り当てる

いくつかの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'を取得します。私は何を間違えていますか?

70
Philip

JavaScriptで closures を作成するのはよくある間違いです。次のような何らかのコールバック関数が必要です。

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

短くて理解しやすいです。

129
Harmen

明確にするために、クリックイベントはループが終了するまで発生しないため、iは20です。

12
Donald
$(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);
  }
});
7
user1490857

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);
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

クリックハンドラーを1回割り当てる(または、少なくとも多くの不要なクロージャーを作成しない)ことで取得できます。すべてのdivを1つのクラス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);
    });
});

slice string method を使用して要素のIDを調べて番号を取得し、最初の文字を取り除きます。

注:使用することをお勧めします

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

の代わりに

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

一般的に、クリックハンドルを多数のアイテムに割り当てる場合、クリックがdomからバブルアップするため、クリックを解釈するコンテナー(高レベルdiv)が必要です。

<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>
2
stancoffyn