为什么事件侦听器只添加到第一个元素?



因此,在单击按钮之后,有这个循环遍历数组并创建包含来自每个数组元素的数据的div。现在,div被注入DOM之后,我向它们添加了一个事件侦听器,但是只有第一个添加的元素响应。/其他人都死了。任何建议吗?

btnLeft.addEventListener("click", function(){
let output = "";
for(let x of array){
output += `<div class="listItem" data-id="${x.id}">
<ul>
<li>Name: ${x.name}</li>
<li>Price: ${x.price}</li>
</ul>
</div>`;
}
leftList.innerHTML = output;
document.querySelector(".listItem").addEventListener("click", function(){
console.log(this.getAttribute("data-id"));
});
});

文档方法querySelector()返回文档中与指定的选择器或选择器组匹配的第一个元素。如果没有找到匹配项,则返回null。

由于document.querySelector(".listItem")只选择与指定选择器匹配的第一个元素,因此事件侦听器只应用于第一个元素。

文档方法querySelectorAll()返回一个静态(非动态)NodeList,表示与指定选择器组匹配的文档元素列表。

尝试使用document.querySelectorAll(".listItem")并通过此循环向所有元素添加事件侦听器。

类似于以下最佳答案:Getting error Uncaught TypeError: document.querySelectorAll(…)addEventListener不是一个函数,它包含了如何使用forEach()向querySelectorAll返回的类中的每个listItem添加侦听器的示例。

您可以为每个项目注册一个eventListener/handler,或者您可以通过为事件注册一个共同的祖先标记(这称为事件委托)来更有效地做到这一点。这样做需要你只拥有addEventListener/event属性一次。该单一祖先标记的所有已存在的或在以后动态添加的后代标记都可以委托给已注册的事件。

详细信息在示例中被注释

let data1 = [{id: "x325", name: "CCTV Hub",  price: 139.99}, {id: "x963", name: "Motion Detector", price: 45.99}, {id: "x117", name: "Flood Light",  price: 89.99}, {id: "x581", name: "Alarm System", price: 325.99}];
let data2 = [{id: "x369", name: "Night Vision Goggles",  price: 349.99}, {id: "x020", name: "Metal Detector", price: 149.99}, {id: "x823", name: "Binoculars",  price: 279.99}];
// Reference menu.list
const list = document.querySelector(".list");
/**
* Register button.btn to the "click" event.
* The event handler is an anonymous function which allows us to
* call another function that paasses a parameter other than 
* the Event Object.
* Note: menu.list is the ancestor tag registered to the "click"
* event only once. Any tag pre-existing or dynamically added
* within menu.list can be delegated to the "click" event.
*/
document.querySelector(".btn").addEventListener("click", function(event) {
createList(data1);
this.disabled = true; // Avoid double clicking
list.addEventListener("click", getID);
});
/**
* Register buttoon.add to the "click" event.
* This eventListener is simular to it's predecessor but it 
* doesn't register menu.list to the "click" event since it 
* already is.
*/
document.querySelector(".add").addEventListener("click", function(event) {
createList(data2); // Avoid double clicking
this.disabled = true;
});
/**
* Creates an array of strings from an array of objects.
* The array is then converted into a single string.
* Then that string is rendered as HTML inside of menu.list.
*/
function createList(objArr) {
const items = objArr.map(obj => {
return `<li data-id="${obj.id}">
<ul>
<li>Name: ${obj.name}</li>
<li>Price: ${obj.price}</li>
</ul>
</li>`;
}).join('');
list.insertAdjacentHTML("beforeend", items);
}
/**
* This named function is an event handler.
* clicked is the tag the user actually clicked.
* If the user clicked a tag that has an ancestor tag with a 
* [data-id] attribute, log that [data-id] value.
*/
function getID(event) {
const clicked = event.target;
if (clicked.closest("[data-id]")) {
console.log(clicked.closest("[data-id]").dataset.id);
}
}
:root {
font: 2.25ch/1.25 "Segoe UI"
}
menu,
ul {
list-style: none;
cursor: pointer;
}
button {
font: inherit;
cursor: pointer;
}
.as-console-row::after {
width: 0;
font-size: 0;
}
.as-console-row-code {
width: 100%;
word-break: break-word;
}
.as-console-wrapper {
min-height: 100%;
max-width: 50%;
margin-left: 50%;
}
<button class="btn">Start List</button>
<button class="add">Add New List</button>
<menu class="list"></menu>

最新更新