Назначить обработчики кликов в цикле - PullRequest
70 голосов
/ 04 ноября 2010

У меня несколько 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 ]

127 голосов
/ 04 ноября 2010

Распространенной ошибкой является создание замыканий в циклах в 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 ) );
  }
});

Обновление от 3 июня 2016 года: , поскольку этот вопрос все еще набирает обороты, а ES6 также набирает популярность, я бы предложил современное решение. Если вы пишете ES6, вы можете использовать ключевое слово let, которое делает переменную i локальной для цикла вместо глобальной:

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

Это короче и проще для понимания.

12 голосов
/ 04 ноября 2010

Для пояснения, я равен 20, потому что событие щелчка не сработало до тех пор, пока цикл не завершится.

7 голосов
/ 05 июня 2013
$(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 голосов
/ 04 ноября 2010

Вы можете обойтись, назначив обработчик щелчка один раз (или, по крайней мере, не делая много ненужных замыканий).Поместите все 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);
    });
});

. Этот код проверяет идентификатор элемента, чтобы получить его номер, используя slice строковый метод для удаления начальногобуквы отключены.

Примечание: Может быть лучше использовать

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

вместо

$('.mydivs').click(function(){
3 голосов
/ 03 ноября 2015

Используя на для прикрепления обработчика 'click', вы можете использовать данные события для передачи ваших данных, например:

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>
2 голосов
/ 04 ноября 2010

Как правило, если вы хотите назначить маркеры кликов большому количеству элементов, вам нужен контейнер (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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...