1

请先浏览代码。

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 的子菜单。提前致谢。

PS我认为问题出在addEventListener。

4

1 回答 1

1

这是一个常见问题,但我会尝试给出比我发现的更好的解释。当您将函数作为参数传递时(就像在定义事件处理程序时一样),javascript 不会评估该函数,而是将函数连同对它的 parent 的引用一起存储scope

在触发事件处理程序之前,不会对函数进行评估。届时,解释器将检查subparent 中的值scope。因为这总是会在你的for循环完成后发生,所以它总是会找到 的最后一个值sub,即你的循环完成sub时的任何值。for因此,您所有的事件侦听器都将使用sub.

我们可以通过创建一个闭包来获得所需的行为。替换这个:

supcont.addEventListener("click",function() {
    toggleVisibility(sub); });

有了这个:

(function(localSub) {
    supcont.addEventListener("click",function() {
        toggleVisibility(localSub);
    });    
})(sub);

之所以可行,是因为我们scope通过调用 IIFE 将每个事件处理程序声明与一个新的父级包装在一起。这迫使事件处理程序保留scopeIIFE 内部的副本(称为在 that 上创建闭包scope)。现在,当事件处理程序查找 时localSub,它将在新的父级中找到它,scope并且它将具有我们想要的值。

于 2013-05-15T14:42:54.670 回答