通过for循环添加事件侦听器

时间:2017-04-06 09:13:32

标签: javascript

我在使用某些JavaScript代码时遇到了一些问题。 我想要做的是将事件侦听器添加到数组中的元素。

问题是,在运行代码之后,只有数组中的最后一个元素才能使eventlistener正常工作,其余的元素都会返回错误。

我假设这是因为我正在使用for循环和eventlisteners的逻辑。 什么是达到预期结果的有效方法?

function addSlider(config) {
var controls = `
        <div id="next"> next </div>
        <div id="previous"> previous </div>`;
var S_wrapper = config.wrapper;
var controls_html = document.createElement("div");
controls_html.setAttribute("id", "ctrl");
controls_html.innerHTML = controls;

var arrayData = config.wrapper.split(",");

for (i = 0; i < arrayData.length; i++) {
    (function(index) {
        document.querySelector(arrayData[i]).appendChild(controls_html);
        var parent = document.querySelector(arrayData[index]);
        console.log(i, index, arrayData[index], parent);

        document.querySelector(arrayData[index]).addEventListener("mouseover", function(){
            this.querySelector("#ctrl").style.display = "block";
        })

        document.querySelector(arrayData[index]).addEventListener("mouseout", function(){
            this.querySelector("#ctrl").style.display = "none";
        })
    })(i);
}

}

2 个答案:

答案 0 :(得分:1)

有几个问题:

  1. 您在每次循环迭代中相同的div移动到新的父级。您的controls_html 不是 HTML,它是对HTMLDivElement对象的引用。这一行:

    document.querySelector(arrayData[i]).appendChild(controls_html);
    

    从它拥有的任何父级(最初没有,但在第一个循环后它是前一个循环中的元素)移动到新父级。

    如果您希望在每个父级中都有新的div,则每次都需要创建一个新的div

  2. 您在多个元素上使用相同的ID ctrl。这是无效的,ID必须是唯一的。之后,当您使用#ctrl时,您将获得浏览器选择给您的任何元素(这是未指定的行为,尽管根据我的经验,它始终是第一个)。

  3. 所以我们需要处理这两个问题。采用最小化更改方法,我们将div创建移动到循环中并将索引添加到ID中:

    function addSlider(config) {
        var controls = `
            <div id="next"> next </div>
            <div id="previous"> previous </div>`;
        var S_wrapper = config.wrapper;
    
        var arrayData = config.wrapper.split(",");
    
        for (i = 0; i < arrayData.length; i++) {
            (function(index) {
                var div = document.createElement("div");
                div.setAttribute("id", "ctrl" + index);
                div.innerHTML = controls;
                var parent = document.querySelector(arrayData[index]);
                parent.appendChild(div);
    
                parent.addEventListener("mouseover", function() {
                    this.querySelector("#ctrl" + index).style.display = "block";
                })
    
                parent.addEventListener("mouseout", function() {
                    this.querySelector("#ctrl" + index).style.display = "none";
                })
            })(i);
        }
    }
    

    但是我退一步看看更广泛的画面。例如,mouseovermouseout都会冒泡,因此您可以在父元素上挂钩,并使用单个处理程序处理它。根本没有理由提供这个身份证;我们可以使用类或类似物识别子div,并且仅在parent内搜索它。您可以使用Array#forEach替换循环及其中的函数。那种事。

    旁注:我注意到你正在使用模板文字(你要分配给controls的东西),这是ES2015(又名“ES6”)中引入的一个功能,但没有使用任何一个其他ES2015功能。所以只是在你没有意识到的情况下标记它......

答案 1 :(得分:0)

PS:我将回答您当前代码中的问题,而不是谈论设计/重构(其他人已对此进行了评论)

您的主要问题是使用id而不是类。请记住,文档中只能存在一个id,否则无法引用它们。

此外,您还在重用controls_html元素,您应该为要添加的每个元素创建一个新元素。 (再次,情况)

我创建了一个fiddle,其中包含代码的工作副本

function addSlider(config) {
    var controls = `
        <div class="next"> next </div>
        <div class="previous"> previous </div>`;

    var S_wrapper = config.wrapper;
    var arrayData = config.wrapper.split(",");

    for (i = 0; i < arrayData.length; i++) {
        (function(index) {
            var controls_html = document.createElement("div");
            controls_html.setAttribute("class", "ctrl");
            controls_html.style.display = 'none';
            controls_html.innerHTML = controls;

            document.querySelector(arrayData[index]).appendChild(controls_html);
            var parent = document.querySelector(arrayData[index]);

            document.querySelector(arrayData[index]).addEventListener("mouseover", function() {
                this.querySelector(".ctrl").style.display = "block";
            })

            document.querySelector(arrayData[index]).addEventListener("mouseout", function() {
                this.querySelector(".ctrl").style.display = "none";
            })
        })(i);
    }
}

addSlider({
    wrapper: '#a,#b,#c'
})
<div id="a">
    1
</div>
<div id="b">
    2
</div>
<div id="c">
    3
</div>