![](/img/trans.png)
[英]Putting a AddEventListener on a button that is in InnerHTML in a for loop
[英]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
});
注意 苏格兰语评论eval
和innerHTML
同样适用于此答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.