JS中的addEventListener无法正常工作 [英] addEventListener in JS not working as expected
问题描述
请先略读代码.
index.html是:
index.html is :
<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是:
script.js is :
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的子菜单.预先感谢.
What I would like to do is when I press supermenu all sub-menus' visibility to be toggled. But I don't know where I have made a mistake. When I press Supmenu0, submenus of Supmenu1 are toggled, not submenus of Supmenu1. Thanks in advance.
P.S.我认为问题出在addEventListener中.
P.S. I think the problem is in addEventListener.
推荐答案
这是一个经常被问到的问题,但是我将尝试给出比我发现的更好的解释.当您将函数作为参数传递时(如定义事件处理程序时),javascript那时不会评估函数,而是将函数及其对父级scope
的引用存储起来.
This is a frequently asked question but I will try to give a better explanation than I have found. When you pass a function as a parameter (as when defining your event handler), javascript does not evaluate the function at that time, but instead stores the function along with a reference to its parent scope
.
在触发事件处理程序之前,函数不会得到评估.那时,解释器将检查父scope
中的sub
的值.由于这总是在您的for
循环完成之后发生,因此它将始终找到sub
的最后一个值,即for
循环完成时的sub
是什么.因此,所有事件侦听器都将使用sub
的最后一个值.
The function does not get evaluated until the event handler is triggered. At that time, the interpreter will check the value of sub
in the parent scope
. Since this will always happen after your for
loop has completed, it will always find the last value of sub
, i.e. whatever sub
was when your for
loop was completed. So all of your event listeners will use the last value of sub
.
We can get the desired behavior by creating a closure. Replace this:
supcont.addEventListener("click",function() {
toggleVisibility(sub); });
与此:
(function(localSub) {
supcont.addEventListener("click",function() {
toggleVisibility(localSub);
});
})(sub);
之所以可行,是因为通过调用IIFE,我们用新的父类scope
包装了每个事件处理程序声明.这迫使事件处理程序将scope
的副本保留在IIFE内(称为在该scope
上创建闭包).现在,当事件处理程序去寻找localSub
时,它将在新的父scope
中找到它,并且它将具有我们想要的值.
The reason this works is because we wrap each event handler declaration with a new parent scope
by invoking an IIFE. This forces the event handler to retain a copy of the scope
inside the IIFE (called creating a closure over that scope
). Now, when the event handler goes looking for localSub
, it will find it in the new parent scope
and it will have the value we want.
这篇关于JS中的addEventListener无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!