Подтвердить что ты не робот

Добавление 'click' прослушивателей событий в цикл

Стандарт рефакторинга onClick в теге html для слушателей столкнулся с проблемой с моим кодом:

var td;
    for (var t=1;t<8;t++){
        td = document.getElementById('td'+t);
        if (typeof window.addEventListener==='function'){
                td.addEventListener('click',function(){
                    console.log(td);
            })}
 }  

Когда элемент td нажат, он предположил, что нажал td с последним индексом из цикла, например. 7
Похоже, eventListeners был заполнен для последнего элемента только в этом цикле.
Инициализация цикла выглядит правильно.
Почему так получилось?

Вот живой код

4b9b3361

Ответ 1

Вам нужно обернуть назначение прослушивателя событий в закрытии, например:

var td;
for (var t = 1; t < 8; t++){
    td = document.getElementById('td'+t);
    if (typeof window.addEventListener === 'function'){
        (function (_td) {
            td.addEventListener('click', function(){
                console.log(_td);
            });
        })(td);
    }
}

Ответ 2

Что происходит

Переменная td определяется вне обработчиков событий, поэтому, когда вы нажимаете на ячейку, вы регистрируете последнее значение, на которое оно было установлено.

Более технически: каждая функция обработчика событий - это замыкание - функция, которая ссылается на переменные из внешней области.

Общее решение

Общее решение этой проблемы - вернуть обработчик события из функции-обертки, передав переменные, которые вы хотите "исправить" в качестве аргументов:

td.addEventListener('click', function(wrapTD) {
    return function() { console.log(wrapTD); }
}(td));

Теперь аргументы привязаны к объему вызываемой функции-обертки.

Упрощенное решение: используйте this

Однако есть еще более простой вариант. В обработчике событий this устанавливается элемент, на котором определен обработчик, поэтому вы можете просто использовать this вместо td:

td.addEventListener('click', function() {
    console.log(this);
});

Еще проще: нет цикла!

Наконец, вы можете полностью избавиться от цикла for и установить один обработчик событий во всей таблице:

var table = document.getElementById('my-table');

table.addEventListener('click', function(e) {
    if (e.target.nodeName.toUpperCase() !== "TD") return;

    var td = e.target;
    console.log(td);
});

Это гораздо лучшее решение для больших таблиц, поскольку вы заменяете несколько обработчиков событий только одним. Обратите внимание: если вы обернете текст в другой элемент, вам нужно будет его адаптировать, чтобы проверить, является ли целевой элемент потомком td.

Ответ 3

Итак, что здесь происходит, так это то, что вы сохраняете переменную td в области действия функции прослушивания событий. Существует только один экземпляр "td", и он обновляется каждый раз, когда цикл цикла повторяется. Таким образом, когда цикл for завершен, значение td теперь устанавливается на элемент '# td7', и ваш обработчик событий просто регистрирует текущее значение td.

В приведенном выше примере вы можете просто зарегистрировать 'this':

var td;
for (var t=1;t<8;t++){
    td = document.getElementById('td'+t);
    if (typeof window.addEventListener==='function'){
      td.addEventListener('click',function(){
        console.log(this);
      });
    }
}

так как 'this' установлен в элемент, для которого событие было связано для выполнения обработчика события.

Я предполагаю, что вы ищете больше ответа о сохранении итератора при создании закрытий из цикла for. Для этого вы хотите определить функцию вне цикла for.

for (var t=1;t<8;t++){
  bind_event(t);
}

function bind_event(t) {
    var td = document.getElementById('td'+t);
    if (typeof window.addEventListener==='function'){
      td.addEventListener('click',function(){
        console.log(td);
      });
    }
}

Таким образом, экземпляр переменной с именем 'td' создается каждый раз при запуске bind_event, и этот экземпляр будет храниться в закрытии для функции прослушивателя событий. Стоит отметить, что 't' в bind_event также является новой переменной.

Ответ 4

Как я понимаю, это происходит из-за закрытия... вы назначаете обработчик событий в рамках оператора FOR. Когда клик происходит, он принимает последнюю версию, если переменная TD в области FOR и записывает ее в журнал.

Ответ 5

следующее должно работать как ожидалось:

  for (var t=1;t<8;t++){
        var td;
        td = document.getElementById('td'+t);
        if (typeof window.addEventListener==='function'){
                td.addEventListener('click',function(){
                    console.log(this);
            })}
 }