Добавление '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
был заполнен для последнего элемента только в этом цикле.
Инициализация цикла выглядит правильно.
Почему так получилось?
Вот живой код
Ответы
Ответ 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);
})}
}