javascript 有没有办法给所有相同的ID添加一个事件队列?

xsuvu9jc  于 12个月前  发布在  Java
关注(0)|答案(3)|浏览(100)

我想建立一个待办事项清单。
我设法让所有的eventListener都能为第一个任务工作,但是对于每个后续任务,这些侦听器都被删除或根本不分配。我尝试了一个forEach循环,但要么我用错了,要么它不工作。现在我不知道我可以做些什么改变,以便所有进一步的任务也能监听这些eventListener。
我试着在close eventlist上使用forEach循环,但是整个close eventlist在每个任务上都停止了工作。

const FORM = document.getElementById("form");
let input = document.getElementById("text");
const CLOSE = document.getElementById("close");
const WRAPPER = document.querySelector(".newWrapper");
const TASK = document.getElementById("task");

FORM.addEventListener("submit", (evt) => {
  evt.preventDefault();

  let div = document.createElement("div");
  div.classList.add("newWrapper");
  let p = document.createElement("p");
  let renderedText = document.createTextNode(input.value);
  p.setAttribute("id", "task");
  p.setAttribute("class", "w-96 bg-white text-center py-3");
  let i = document.createElement("i");
  i.setAttribute("id", "close")
  i.setAttribute("class", "fa fa-x fa-2x h-12 p-2 cursor-pointer");

  p.appendChild(renderedText);
  div.appendChild(p);
  div.appendChild(i)
  document.body.appendChild(div);

});

CLOSE.addEventListener("click", () => {
  document.body.removeChild(WRAPPER)
});

TASK.addEventListener("click", () => {
  WRAPPER.setAttribute("class", "flex justify-center");
  if (TASK.className !== "checked w-96 py-3 text-center") {
    TASK.setAttribute("class", "checked w-96 py-3 text-center");
  } else {
    TASK.setAttribute("class", "w-96 bg-white text-center py-3");
  }

});
<script src="https://cdn.tailwindcss.com"></script>
  
<div class="flex justify-center ">
  <h1 class="text-3xl">Todos</h1>
</div>
<form id="form" class="flex justify-center items-center">
  <input id="text" type="text" class="w-80 bg-white rounded-md py-3" placeholder="Essen gehen...">
  <i type="submit" class="fa-solid fa-check hover:cursor-pointer"></i>
</form>
<br>
<br>
<div class="newWrapper">
  <p id="task" class="w-96 bg-white text-center py-3">get food</p>
  <i id="close" class="fa fa-x fa-2x h-12 p-2 cursor-pointer"></i>
</div>
<div class="newWrapper">
  <p id="task" class="w-96 bg-white text-center py-3">get food</p>
  <i id="close" class="fa fa-x fa-2x h-12 p-2 cursor-pointer"></i>
</div>
balp4ylt

balp4ylt1#

在任何给定的文档中,ID值都必须是唯一的。getElementById只返回一个元素。(在一个重复使用相同id值的无效文档中,它将返回第一个值,尽管我不知道在任何地方指定了这一点。不要这样做。)
相反,使用一个类。然后,要么:
1.将事件挂接到所有这些元素都在其中的元素上(如果没有更具体的内容,则为body元素),然后在 * 如果 * 事件通过其中一个元素时执行操作。这被称为“事件委托”。

document.body.addEventListener("click", (event) => {
    // Did the event pass through an element with `class="task"`?
    const task = event.target.closest(".task");
    if (task /* && event.currentTarget.contains(task) */) {
        // Yes, handle it:
        const wrapper = task.closest(".newWrapper");
        // ...do something with `wrapper`, probably via `wrapper.classList`'s `toggle`, `add`, and/or `remove` methodss...
    }
});

其中一个关键是元素上的closest方法,该方法查找元素祖先(从元素本身开始)中与给定CSS选择器匹配的第一个元素。
如果使用document.body执行此操作,则不需要对contains的删除调用,但如果在DOM树的更深处使用委托,则可能需要它,以避免将 * 祖先 * 元素匹配到您正在处理事件的元素。这是相对罕见的,但值得注意。
1.查找所有匹配的元素(例如,通过document.querySelectorAll)并将处理程序连接到每个元素。

function taskClickHandler(event) {
    const wrapper = this.closest(".newWrapper");
    // ...do something with `wrapper`, probably via `wrapper.classList`'s `toggle`, `add`, and/or `remove` methodss...
}
for (const task of document.querySelectorAll(".task")) {
    task.addEventHandler("click", taskClickHandler);
}

每一个都有优点和缺点。事件委托特别适合于动态添加和删除元素的情况,即使不动态添加和删除元素,它也能正常工作。它对来自同一事件的其他事件处理程序的干扰稍微敏感一些。
更多探索:

avwztpqn

avwztpqn2#

下面是使用委托的代码。
我也添加了相关的库
我将todos添加到它自己的div中,以便从那里委托

window.addEventListener("DOMContentLoaded", () => {
  const form = document.getElementById("form");
  const input = document.getElementById("text");
  const todoWrapper = document.getElementById("todoWrapper");

  form.addEventListener("submit", (evt) => {
    evt.preventDefault();
    let div = document.createElement("div");
    div.classList.add("newWrapper");
    let p = document.createElement("p");
    let renderedText = document.createTextNode(input.value);
    p.setAttribute("class", "task w-96 bg-white text-center py-3");
    let i = document.createElement("i");
    i.setAttribute("class", "close fa fa-x fa-2x h-12 p-2 cursor-pointer");
    p.appendChild(renderedText);
    div.appendChild(p);
    div.appendChild(i)
    todoWrapper.appendChild(div);
  });

  todoWrapper.addEventListener("click", (e) => {
    const tgt = e.target; 
    if (tgt.matches("i.close")) {
      tgt.closest("div.newWrapper").remove();
      return
    }
    const wrapper = tgt.closest("p.task");
    if (!wrapper) return;
    wrapper.classList.toggle("checked")
  });
});
.newWrapper { border: 1px solid black }
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>

<div class="flex justify-center ">
  <h1 class="text-3xl">Todos</h1>
</div>
<form id="form" class="flex justify-center items-center">
  <input id="text" type="text" class="w-80 bg-white rounded-md py-3" placeholder="Essen gehen...">
  <i type="submit" class="fa-solid fa-check hover:cursor-pointer"></i>
</form>
<div id="todoWrapper"></div>
3xiyfsfu

3xiyfsfu3#

请注意,id不能与许多html元素相同,而是使用class。这是一个例子,看一看,理解它,然后将它应用到你的代码中。

<div class="box">Box 1</div>
<div class="box">Box 2</div>
<div class="box">Box 3</div>
const boxes = document.querySelectorAll('.box');

boxes.forEach(box => {
  box.addEventListener('click', function handleClick(event) {
    console.log('box clicked', event);

    box.setAttribute('style', 'background-color: yellow;');
  });
});

相关问题