AddEventListener, использующий для цикла и пропущенных значений
Я пытаюсь добавить слушатель событий к нескольким объектам, используя цикл for, но в итоге все слушатели нацеливаются на один и тот же объект → последний.
Если я добавлю слушателей вручную, определив boxa и boxb для каждого экземпляра, это сработает. Я думаю, это цикл for addEvent, который работает не так, как я надеялся. Может быть, я вообще использую неправильный подход.
Пример использования 4 класса = "контейнер"
Триггер на контейнере 4 работает так, как он должен.
Триггер для контейнера 1,2,3 триггерного события в контейнере 4, но только если триггер уже активирован.
// Function to run on click:
function makeItHappen(elem, elem2) {
var el = document.getElementById(elem);
el.style.backgroundColor = "red";
var el2 = document.getElementById(elem2);
el2.style.backgroundColor = "blue";
}
// Autoloading function to add the listeners:
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);
}
<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>
Ответы
Ответ 1
Затворы!: D
Этот исправленный код работает так, как вы хотели:
// Function to run on click:
function makeItHappen(elem, elem2) {
var el = document.getElementById(elem);
el.style.backgroundColor = "red";
var el2 = document.getElementById(elem2);
el2.style.backgroundColor = "blue";
}
// Autoloading function to add the listeners:
var elem = document.getElementsByClassName("triggerClass");
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
}
<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>
Ответ 2
Вы сталкиваетесь с проблемой scope/close как function(){makeItHappen(boxa,boxb);}
ссылки boxa и boxb, а затем всегда один из следующих элементов.
Чтобы решить проблему:
function makeItHappenDelegate(a, b) {
return function(){
makeItHappen(a, b)
}
}
// ...
elem[i].addEventListener("click", makeItHappenDelegate(boxa,boxb), false);
Ответ 3
Вы можете использовать функцию Binding.You не нужно использовать закрытие. Смотрите ниже:
До
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);
}
}
Ответ 4
У меня также была эта проблема некоторое время назад.
Я решил это, используя функцию "добавляет" вне цикла, чтобы назначить события, и он отлично работал.
Ваш script должен выглядеть.
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";
}
Ответ 5
Это из-за закрытия.
Проверьте это: 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, 3.