javascript - 事件冒泡导致事件向元素的子级注册

我正在尝试制作一个从 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.currentTargetlistItem,而不是 event.target