我正在尝试使用for循环向多个对象添加事件侦听器,但最终会使用针对同一对象的所有侦听器 - >最后一个。
如果我通过为每个实例定义boxa和boxb来手动添加侦听器,它就可以工作。我想这就是addEvent for-loop,它不像我希望的那样工作。也许我完全使用了错误的方法。
使用4个class =“container”的示例 容器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>
答案 0 :(得分:109)
闭包! :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);
}
由于variable hoisting,var
声明会移到范围的顶部。由于JavaScript没有块范围(for
,if
,while
等),因此它们会移到函数的顶部。 更新:从ES6开始,您可以使用let
来获取块范围变量。
当您的代码运行时,会发生以下情况:在for
循环中添加单击回调并指定boxa
,但在下一次迭代中它的值会被覆盖。当click事件触发回调运行并且boxa
的值 始终列表中的最后一个元素时。
使用闭包(关闭boxa
,boxb
等的值)将值绑定到单击处理程序的范围。
此类JSLint或JSHint等代码分析工具将能够捕获此类可疑代码。如果您正在编写大量代码,那么花些时间学习如何使用这些工具是值得的。有些IDE内置它们。
答案 1 :(得分:11)
您将范围/结束问题视为function(){makeItHappen(boxa,boxb);}
boxa 和 boxb 引用,然后始终是最后一个元素。
解决问题:
function makeItHappenDelegate(a, b) {
return function(){
makeItHappen(a, b)
}
}
// ...
elem[i].addEventListener("click", makeItHappenDelegate(boxa,boxb), false);
答案 2 :(得分:6)
你可以使用Function Binding。你不需要使用闭包。见下文:
<强>之前强>:
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);
}
}
答案 3 :(得分:1)
这是因为关闭。
示例代码和您的代码基本相同,对于那些不知道“封闭”的人来说,这是一个常见的错误。
简单来说,当你在addEvents()
中创建一个处理函数时,它不只是从i
的环境中访问变量addEvents()
,而且还“记住” i
。
由于您的处理程序“记住”i
,因此i
执行后变量addEvents()
不会消失。
因此,当调用处理程序时,它将使用i
,但变量i
现在在for循环之后为3。
答案 4 :(得分:0)
前一段时间我也遇到过这个问题。 我通过在循环外部使用“添加”功能来解决它,分配事件,并且它工作得很好。
您的脚本应该是这样的。
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";
}