簡體   English   中英

如何在此for循環中將EventListener添加到每個innerHTML + =?

[英]How can I addEventListener to each innerHTML += in this for loop?

我正在嘗試在一些重復的innerHTML上添加事件偵聽器。 對於由innerHTML添加的所有HTML,IE也需要在其上添加click事件。

為了使事情復雜化,我還要從名稱數據下導入的另一個JS文件中導入數據集。 如您在代碼中所看到的,我需要事件偵聽器內部的數據特定於innerHTML的for循環迭代,以便當我觸發事件偵聽器時,可以看到正確的對應數據。

這是我的嘗試:

JS:

import data from './data.js';
import img from './images.js';

export const lists = () => {
  const main = document.getElementById('main');

  main.innerHTML = `
  <div class="main-container">
    <div class="flex-between row border-bottom">
      <div class="flex new-list">
        <img class="create-img img-radius" src="${img.symbols[0]}" alt="Delete Bin">
        <h3>New List</h3>  
      </div>
      <div class="flex-between sections">
        <h3 class="text-width flex-c">Items:</h3>
        <h3 class="text-width flex-c">Reminders:</h3>
        <h3 class="text-width flex-end">Created:</h3>
      </div>
    </div>
    <div id="lists"></div>
  </div>
  `;

  const lists = document.getElementById('lists');

  for (let i = 0; i < data.lists.length; i++) {
    let obj = eval(data.lists[i]);
    let totalReminders = getTotalReminders(obj);

    lists.innerHTML += `
    <div class="flex-between row list">
      <h4>${obj.name}</h4>
      <div class="flex-between sections">
        <h4 class="number-width flex-c">${obj.items.length}</h4>
        <h4 class="number-width flex-c">${totalReminders}</h4>
        <div class="text-width flex-end">
          <h4 class="date">${obj.created}</h4>
          <img class="img-radius" src="${img.symbols[3]}" alt="Delete Bin">
        </div>
      </div>
    </div>
    `;

    const list = document.querySelector('.list');

    list.addEventListener('click', () => { // click event
      listNav.listNav(obj.name);
      listSidebarL.listSidebarL();
      listSidebarR.listSidebarR();
      listMain.listMain(obj.items);
    });
  };
};

const getTotalReminders = passed => { // find total reminders
  let total = 0;

  for (let i = 0; i < passed.items.length; i++) {
    total += passed.items[i].reminders;
  };

  return total;
};

目前,僅innerHTML +=的第一次迭代附加了事件偵聽器,當我單擊它時,我看到的數據應該與上次迭代相對應。

我在這里做錯了什么?

您需要移動設置事件處理程序的代碼,以使其位於for循環之外,並在該循環結束后運行。 然后,而不是.querySelector()只返回第一個匹配的元素,你需要.querySelectorAll()返回所有匹配的元素。 之后,您將遍歷所有這些元素並設置處理程序。

您還需要更改obj變量的聲明方式,使其位於for循環之外。 為此,只需在循環之前聲明它,但在循環內部分配它:

let obj = null; // Now, obj is scoped so it can be accessed outside of the loop
for (let i = 0; i < data.lists.length; i++) {
  obj = eval(data.lists[i]);

並且,在for循環結束后放置以下內容:

// Get all the .list elements into an Array
const list = Array.prototype.slice.call(document.querySelectorAll('.list'));

// Loop over the array and assign an event handler to each array item:
list.forEach(function(item){
  item.addEventListener('click', () => { 
    listNav.listNav(obj.name);
    listSidebarL.listSidebarL();
    listSidebarR.listSidebarR();
    listMain.listMain(obj.items);
  });
});

綜上所述,您在這里的方法確實不是很好。 除了使用eval()進行任何操作外,幾乎總是存在另一種選擇,並且由於其安全性和性能影響,通常避免使用.innerHTML 循環使用它幾乎總是一個壞主意。 您確實應該使用DOM API來創建新元素,對其進行配置並將它們注入DOM。 如果必須使用.innerHTML ,則在循環中構建一個字符串,然后在循環之后,通過.innerHTML將字符串注入DOM一次。

一種選擇是查看事件委托/冒泡 這里的基本原理是將事件處理程序添加到父對象,在本例中為<div id="lists"></div> 然后,在觸發事件時,您查詢該事件的目標以查看其是否與您的元素匹配。

使用此技術,在添加新項目時不必重新綁定事件處理程序,特別是在通過用戶交互添加項目時特別有用。

在您的情況下,它將類似於:

export const lists = () => {
  const main = document.getElementById('main');

  main.innerHTML = `
  <div class="main-container">
    <div class="flex-between row border-bottom">
      <div class="flex new-list">
        <img class="create-img img-radius" src="${img.symbols[0]}" alt="Delete Bin">
        <h3>New List</h3>  
      </div>
      <div class="flex-between sections">
        <h3 class="text-width flex-c">Items:</h3>
        <h3 class="text-width flex-c">Reminders:</h3>
        <h3 class="text-width flex-end">Created:</h3>
      </div>
    </div>
    <div id="lists"></div>
  </div>
  `;

  const lists = document.getElementById('lists');

   //Now that the parent element is added to the DOM
   //Add the event handler
   lists.addEventListener("click",function(e) {
   // e.target was the clicked element
   if (e.target && e.target.matches(".list")) {
       listNav.listNav(obj.name);
       listSidebarL.listSidebarL();
       listSidebarR.listSidebarR();
       listMain.listMain(obj.items);
   }

   //Add Items etc    
});

注意 蘇格蘭語評論evalinnerHTML同樣適用於此答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM