addEventListener использование для цикла и передачи значений [дубликат]
этот вопрос уже есть ответ здесь:
JavaScript закрытие внутри петли – простой практический пример
39 ответы
Я пытаюсь добавить прослушиватель событий к нескольким объектам, используя цикл for, но в конечном итоге все слушатели нацелены на один и тот же объект --> последний.
Если я добавлю слушателей вручную, определив boxa и boxb для каждого экземпляра, это работает. Я думаю, что это addEvent for-loop, который не работает так, как я надеялся. Может быть, я использую неправильный подход вообще.
пример использования 4 класса="контейнер"
Триггер на контейнере 4 работает так, как он должен.
Триггер на контейнере 1,2,3 событие триггера на контейнере 4, но только если триггер уже активирован.
функция для запуска по щелчку мыши:
function makeItHappen(elem, elem2){
var el = document.getElementById(elem);
el.style.transform = "flip it";
var el2 = document.getElementById(elem2);
el2.style.transform = "flip it";
}
функция автозапуска для добавления слушатели:
function addEvents(){
var elem = document.getElementsByClassName("triggerClass");
for(var i=0; i < elem.length; i+=2){
var k = i + 1;
var boxa = elem[i].parentNode.id;
var boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false);
elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false);
}
}
HTML-код
<div class="container">
<div class="one" id="box1">
<p class="triggerClass">some text</p>
</div>
<div class="two" id="box2">
<p class="triggerClass">some text</p>
</div>
</div>
<div class="container">
<div class="one" id="box3">
<p class="triggerClass">some text</p>
</div>
<div class="two" id="box4">
<p class="triggerClass">some text</p>
</div>
</div>
5 ответов:
закрытие! : D
этот фиксированный код работает так, как вы намеревались:
for (var i = 0; i < elem.length; i += 2) { (function () { var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function() { makeItHappen(boxa,boxb); }, false); elem[k].addEventListener("click", function() { makeItHappen(boxb,boxa); }, false); }()); // immediate invocation }
почему это исправить?
for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); }на самом деле не строгий JavaScript. Это интерпретируется так:
var i, k, boxa, boxb; for(i=0; i < elem.length; i+=2){ k = i + 1; boxa = elem[i].parentNode.id; boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); }из-за переменной поднимая на
varобъявления перемещаются в верхнюю часть области. Поскольку JavaScript не имеет области видимости блока (for,if,whileetc.) они перемещаются в верхнюю часть функции. обновление: С ES6 вы можете использоватьletчтобы получить переменные области блока.при запуске кода происходит следующее: в
forцикл вы добавляете обратные вызовы щелчка и вы назначаетеboxa, но его значение перезаписывается в следующей итерации. Когда событие click срабатывает, выполняется обратный вызов и значениеboxaи всегда последний элемент в списке.С помощью закрытия (закрытие значений
boxa,boxbetc)вы привязываете значение к области обработчика щелчка.
инструменты анализа кода JSLint или JSHint сможет поймать подозрительный код, как это. Если вы пишете много кода, стоит потратить время, чтобы узнать, как использовать эти инструменты. Некоторые IDE имеют их встроенный.
вы столкнулись с проблемой объема / закрытия как
function(){makeItHappen(boxa,boxb);}boxa и boxb ссылки, то всегда последний элемент(ы).решение проблемы:
function makeItHappenDelegate(a, b) { return function(){ makeItHappen(a, b) } } // ... elem[i].addEventListener("click", makeItHappenDelegate(boxa,boxb), false);
Вы можете использовать функции привязки.Вам не нужно использовать закрытие.Смотрите ниже:
до:
function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); } }после:
function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", makeItHappen.bind(this, boxa, boxb), false); elem[k].addEventListener("click", makeItHappen.bind(this, boxa, boxb), false); } }
это из-за закрытий.
проверьте это: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake
пример кода и ваш код по существу одинаковы, это распространенная ошибка для тех, кто не знает "закрытия".
проще говоря, когда вы создаете функцию обработчика внутри
addEvents(), Он не просто обращается к переменнойiСaddEvents()окружение, но он также "помнит"i.и потому, что ваш обработчик "помнит"
iпеременнаяiне исчезнет послеaddEvents()был казнен.таким образом, когда вызывается обработчик, он будет использовать
iно переменнаяiтеперь, после for-loop, 3.
У меня тоже была эта проблема некоторое время назад. Я решил его с помощью функции" добавляет " вне цикла, чтобы назначить события, и он работал отлично.
ваш скрипт должен выглядеть.
function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; //- edit ---------------------------| adds(boxa, boxb); } } //- adds function ----| function adds(obj1, obj2){ obj1.addEventListener("click", function(){makeItHappen(obj1, obj2);}, false); obj2.addEventListener("click", function(){makeItHappen(obj1, obj2);}, false); } //- end edit -----------------------| function makeItHappen(elem, elem2){ var el = document.getElementById(elem); el.style.transform = "flip it"; var el2 = document.getElementById(elem2); el2.style.transform = "flip it"; }
Comments