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 はその時点で関数を評価しませんが、代わりに関数をその親への参照と共に格納します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 を呼び出して、各イベント ハンドラー宣言を新しい親でラップするためです。これにより、イベント ハンドラーscopeは IIFE 内の のコピーを保持するようになります (その 上のクロージャーの作成と呼ばれscopeます)。これで、イベント ハンドラーが を探しに行くlocalSubと、新しい親でそれが見つかり、必要なscope値が含まれます。

于 2013-05-15T14:42:54.670 に答える