2017-04-06 53 views
0

我在使用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); 
} 

}

+1

你有没有考虑过将事件监听器添加到所有渲染的arrayData的父节点,所以你只需要一个处理程序而不是每个元素相同?但是,是的,你的问题是一个关闭相关的问题,我会尝试找到重复。 – Shilly

回答

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>

1

有几个问题:

  1. 你是搬家在每次循环迭代中将相同的div分配给新的父级。您的controls_html不是 HTML,它是对HTMLDivElement对象的引用。这条线:

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

    移动它无论从任何父它(最初没有,但第一循环结束后它从以前的循环中的元素)为新的父。

    如果你想在每个家长中新建一个div,你需要每次创建一个新的div

  2. 对多个元素使用相同的ID 。这是无效的,ID必须是唯一的。后来,当你使用#ctrl时,你会得到浏览器选择给你的任何元素(这是未指定的行为,虽然根据我的经验,它总是第一个)。

所以我们需要处理这两个问题。以最小的 - 改变到你的方法解决方案,我们移动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都会冒泡,因此您可以将它们绑定到父元素上并使用单个处理程序处理。这个ID也可能没有理由;我们可以识别一个班级或类似的子div,并且只能在parent之内找到它。你可以用Array#forEach替换循环及其中的函数。之类的东西。


附注:我注意到你使用文字模板(你分配给controls的东西),这是在ES2015(又名“ES6”)中引入的功能,但不使用任何其他ES2015功能。所以只是举起,以防万一你没有意识到...