首先请浏览代码。
index.html是:
<html><head><title>Home</title><script src="js/script.js"></script></head>
<body onLoad="init()">
<ul class="sup" id="sup">
<li class="supitem">
<a href="#" class="supcont">Home<div class="v"></div></a>
<ul class="sub">
<li class="subitem"><a href="#" class="subcont">Home1</a></li>
<li class="subitem"><a href="#" class="subcont">Home2</a></li>
<li class="subitem"><a href="#" class="subcont">Home3</a></li>
</ul>
</li>
<li class="supitem">
<a href="#" class="supcont">Blog<div class="v"></div></a>
<ul class="sub">
<li class="subitem"><a href="#" class="subcont">Blog1</a></li>
<li class="subitem"><a href="#" class="subcont">Blog2</a></li>
<li class="subitem"><a href="#" class="subcont">Blog3</a></li>
</ul>
</li>
</ul>
</body>
</html>
script.js是:
function init() {
var sky = 0;
var sup = document.getElementById("sup");
var supitems = sup.getElementsByClassName("supitem");
for (var i = 0, ln = supitems.length; i < ln; i++) {
var supconts = supitems[i].getElementsByClassName("supcont");
var subs = supitems[i].getElementsByClassName("sub");
var supcont = supconts[0];
supcont.innerHTML = "SuperMenu"+i;
if (subs.length > 0) {
var sub = subs[0];
supcont.addEventListener("click",function() {
toggleVisibility(sub); });
supcont.style.background = "#"+sky+sky+sky;
sub.style.background = "#"+sky+sky+sky;
sky += 4;
}
}
}
function toggleVisibility(object) {
object.style.visibility =
(object.style.visibility == "hidden" ?"visible" :"hidden");
}
我想要做的是当我按下超级菜单切换所有子菜单的可见性时。但我不知道我在哪里弄错了。当我按下Supmenu0时,Supmenu1的子菜单被切换,而不是Supmenu1的子菜单。提前谢谢。
P.S。我认为问题出在addEventListener。
答案 0 :(得分:1)
这是一个经常被问到的问题,但我会尝试提供比我发现的更好的解释。当您将函数作为参数传递时(如定义事件处理程序时),javascript不会在此时评估函数,而是存储函数以及对其父scope
的引用。
在触发事件处理程序之前,不会对该函数进行求值。那时,口译员将检查父sub
中scope
的值。由于这将始终在for
循环完成后发生,因此始终会找到sub
的最后一个值,即sub
循环完成时的for
。因此,所有事件侦听器都将使用sub
的最后一个值。
我们可以通过创建closure来获得所需的行为。替换这个:
supcont.addEventListener("click",function() {
toggleVisibility(sub); });
用这个:
(function(localSub) {
supcont.addEventListener("click",function() {
toggleVisibility(localSub);
});
})(sub);
这是有效的原因是因为我们通过调用IIFE将每个事件处理程序声明包装为新的父scope
。这会强制事件处理程序在IIFE中保留scope
的副本(称为在scope
上创建一个闭包)。现在,当事件处理程序查找localSub
时,它会在新的父scope
中找到它,它将具有我们想要的值。