我尝试使用 for 循环将事件监听器添加到多个对象,但最终所有监听器都针对同一对象 --> 最后一个。
如果我通过为每个实例定义 boxa 和 boxb 手动添加监听器,它就可以工作。我猜是 addEvent for 循环没有按我希望的方式工作。也许我完全使用了错误的方法。
示例使用 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>
关闭! :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>
为什么这样可以解决问题?
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 没有 block 作用域(for
、if
、while
等),它们被移动到函数的顶部。 更新:从 ES6 开始,您可以使用 let
获取 block 作用域变量。
当您的代码运行时会发生以下情况:在 for
循环中您添加了点击回调并分配了 boxa
,但它的值在下一次迭代中被覆盖。当点击事件触发回调时,boxa
的值始终是列表中的最后一个元素。
使用闭包(关闭 boxa
、boxb
等的值)将值绑定(bind)到点击处理程序的范围。
代码分析工具,如JSLint或 JSHint将能够像这样捕获可疑代码。如果您正在编写大量代码,那么花时间学习如何使用这些工具是值得的。一些 IDE 内置了它们。