JS中的addEventListener无法正常工作 [英] addEventListener in JS not working as expected

查看:102
本文介绍了JS中的addEventListener无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请先略读代码.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆