我正在尝试制作一个从 API 动态添加元素的下拉列表。当用户在下拉列表中选择一个项目时,它应该向该项目添加一个名为“current”的类。列表中只有一个下拉项可以应用“当前”类。
我已成功创建 HTML 元素 (listItem) 并将它们附加到列表中。但是,当我尝试添加事件侦听器时,该事件会在子元素 img 和 div 中注册,并带有文本,这样当用户单击它们时,会在此处应用“current”类而不是父节点。
我阅读了“事件冒泡”,但不确定这是否是我的问题。
document.addEventListener('DOMContentLoaded', async () => {
const dropDownToggle = document.querySelector('.w-dropdown-toggle')
const dropDownList = document.querySelector('.w-dropdown-list')
const countries = await getCountries();
countries.forEach((country) => {
const countryName = country.name.common;
const cca2 = country.cca2;
const svgUrl = country.flags.svg;
let prefix = country.idd.root + country.idd.suffixes?.[0]
prefix = Number.isNaN(prefix) ? prefix="" : prefix
//console.log(countryName, cca2, prefix)
const listItem = createListItem(countryName, cca2, svgUrl, prefix);
// Bad code here: <a> tag gets event listener but so do its children
listItem.addEventListener("click", (event) => {
console.log(event);
//console.log(event);
//document.querySelector('current')?.classList.remove('current');
//document.querySelector('current').ariaSelected = false;
console.log('hello')
event.target.classList.add("current");
event.target.ariaSelected = true;
console.log('goodbye')
});
dropDownList.append(listItem);
})
});
const getCountries = async () => {
let url = 'https://restcountries.com/v3.1/all'
const response = await fetch(url)
const data = await response.json();
return data;
}
const createListItem = (countryName, cca2, svgUrl, prefix) => {
const template = `
<a data-element="item" aria-role="option" aria-selected="false" href="#" class="dropdown_item w-inline-block" tabindex="0"><img src="${svgUrl}" loading="lazy" data-element="flag" alt="" class="dropdown_flag"><div data-element="value" class="dropdown_text">${cca2}</div></a>
`
const listItem = document.createElement("template");
listItem.innerHTML = template.trim();
return listItem.content.firstElementChild
}
回答1
这是意料之中的。 event.target
是实际单击的最里面的元素,而不是安装事件侦听器的元素。
要使用后者,只需参考 event.currentTarget
或 listItem
,而不是 event.target
。