如何为动态子项分配单击事件侦听器?

时间:2021-04-27 10:18:14

标签: javascript events dynamic listener children

我有一个包含多个元素的父容器,它不是一个明确定义的元素数量,它是在用户开始在输入字段中输入内容时使用 API 生成的。这些元素也是其他元素的父元素。 (下面我举个例子)

这个想法是,一旦用户单击该元素,我想显示一个包含有关该特定元素的更多信息的叠加层。听起来不错,但到目前为止我尝试过的东西都不起作用。

我尝试在容器上添加一个事件侦听器。考虑一下这个基本的 HTML 模板。

<ul>
  <li><span>Item 1</span><span>X</span></li>
  <li><span>Item 2</span><span>X</span></li>
  <li><span>Item 3</span><span>X</span></li>
  <li><span>Item 4</span><span>X</span></li>
</ul>

<form>
  <input type="text" id="test">
</form>

所以这里我们有一个 UL 是父元素,LI 是它的子元素。但是,LI 也是应该显示一些重要信息的 span 标签的父级,因此我无法删除这些标签。 输入字段在这里只是为了动态添加一些东西,模仿我的 API 的工作方式。

就像我说的,我尝试在 UL 父级上添加一个事件侦听器 >>

  const items = ul.querySelectorAll('li');
  items.forEach(item => item.addEventListener('click', function(e) {
  console.log(this);
  }));
});
});

然后我尝试为每个项目添加一个事件侦听器,但不是在我单击它们时一次记录一个项目,而是记录一个、两个、三个等等。 我觉得我在这里错过了一些东西,我不知道它是什么。你们能帮我吗?

稍后编辑:我找到了这个解决方案,但它对我来说似乎不是很优雅,而且如果我稍后更改内容(例如添加更多子项等),它很容易出现错误。

ul.addEventListener('click', e => {
  const items = ul.querySelectorAll('li');
  if(e.target.tagName === 'LI' || e.target.parentElement.tagName === 'LI') {
    if(e.target.tagName === 'LI') {
      e.target.remove();
    } else if(e.target.parentElement.tagName === 'LI') {
      e.target.parentElement.remove();
    }
  }
});

2 个答案:

答案 0 :(得分:1)

您可以使用函数 Element.closest() 来查找父元素。

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

ul.addEventListener('click', e => {
  let li = e.target.closest('LI');
  li.remove();
});

document.forms.newitem.addEventListener('submit', e => {
  e.preventDefault();
  let newitem = document.createElement('LI');
  newitem.innerText = e.target.test.value;
  ul.appendChild(newitem);
});
<ul>
  <li><span>Item 1</span><span>X</span></li>
  <li><span>Item 2</span><span>X</span></li>
  <li><span>Item 3</span><span><em>X</em></span></li>
  <li>Item 4 X</li>
</ul>

<form name="newitem">
  <input type="text" name="test">
</form>

答案 1 :(得分:0)

每次单击一行时都会获得所有行事件的原因是,您在 ul 元素中添加了一个事件单击,而您只需要在 li 元素中添加它

一种与您非常相似的方式:

let ul = document.querySelector("ul");

const items = ul.querySelectorAll("li");
items.forEach((item) =>
  item.addEventListener("click", function (e) {
    let getTargetRow = e.target.parentElement;
    if (getTargetRow.nodeName === "LI"){ 
     console.log("the line removed:",getTargetRow.textContent);
     getTargetRow.remove();
    }
  })
);
  <ul>
    <li><span>Item 1</span><span>X</span></li>
    <li><span>Item 2</span><span>X</span></li>
    <li><span>Item 3</span><span>X</span></li>
    <li><span>Item 4</span><span>X</span></li>
  </ul>

  <form>
    <input type="text" id="test" />
  </form>