2017-04-06 110 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功能。所以只是舉起,以防萬一你沒有意識到...