You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

待办列表删除按钮事件重复触发问题求助

待办列表删除按钮重复触发问题分析与解决

问题原因

你每次点击添加待办项的按钮时,都会通过document.querySelectorAll选中所有已存在的删除图标,然后给每一个图标重新绑定一次点击事件。举个例子:

  • 添加第1个待办项:给这个项的删除图标绑1次事件
  • 添加第2个待办项:再次选中所有2个删除图标,各绑1次事件 → 第一个图标现在有2个事件监听
  • 添加第3个待办项:选中所有3个删除图标,各绑1次事件 → 第一个图标有3个事件监听

所以点击第一个删除图标时,会触发和列表项数相同次数的事件;最后一个图标是刚添加的,只被绑定了1次,所以仅触发1次。

性能影响

这种重复绑定事件的做法有两个明显的性能问题:

  • 内存浪费:每多添加一个待办项,就会给所有旧的删除图标多绑一次事件,事件监听的数量会随着项数增长而指数级增加,占用更多内存。
  • 响应变慢:触发事件时多个回调同时执行,不仅逻辑混乱,还会拖慢页面的响应速度。

修复方案

方案1:仅给新添加的项绑定事件

不用选中所有删除图标,只给刚创建的待办项里的删除按钮绑定事件,避免重复绑定:

const arr = [];
addTodo.addEventListener("click", (e) => {
  const todoTxt = document.querySelector(".input--form__txt").firstElementChild;
  const c1 = new CreateTodo(todoTxt.value);
  arr.push(c1);
  todoTxt.value = "";
  
  let newLi = document.createElement(`li`);
  newLi.classList.add("todoitem");
  newLi.innerHTML = `<span class="todoitem--subject">${c1.title}</span>
  <span class="todoitem--detail">
    <span class="todoitem--detail__date">${c1.createdAt[0]}</span>
    <span class="todoitem--detail__select">
    <input type="checkbox" onchange="checkboxstatus(this)" value="${c1.id}"/>
    </span>
    <span class="todoitem--detail__delete">
    <img src="./Assets/Img/trash.svg" alt=""/>
    </span>
  </span>`;
  toDoList.appendChild(newLi);
  
  // 只给当前新添加的项的删除按钮绑事件
  const deleteBtn = newLi.querySelector(".todoitem--detail__delete");
  deleteBtn.addEventListener("click", () => {
    // 从数组中移除对应项(通过id匹配,避免索引混乱)
    const targetIndex = arr.findIndex(item => item.id === c1.id);
    if (targetIndex !== -1) {
      arr.splice(targetIndex, 1);
    }
    // 移除DOM元素
    newLi.remove();
    console.log(arr);
  });
});

方案2:使用事件委托(更优)

利用事件冒泡特性,只给父元素toDoList绑定一次事件,统一处理所有删除按钮的点击。这种方法不需要给每个按钮单独绑事件,性能更优,也从根源上避免了重复绑定问题:

const arr = [];
// 先给父元素绑定一次事件监听
toDoList.addEventListener("click", (e) => {
  // 判断点击的是否是删除按钮区域
  const deleteBtn = e.target.closest(".todoitem--detail__delete");
  if (!deleteBtn) return;
  
  // 找到对应的待办项DOM元素
  const todoItem = deleteBtn.closest(".todoitem");
  // 获取待办项的id
  const todoId = todoItem.querySelector('input[type="checkbox"]').value;
  
  // 从数组中移除对应项
  arr = arr.filter(item => item.id !== todoId);
  // 移除DOM元素
  todoItem.remove();
  console.log(arr);
});

addTodo.addEventListener("click", (e) => {
  const todoTxt = document.querySelector(".input--form__txt").firstElementChild;
  const c1 = new CreateTodo(todoTxt.value);
  arr.push(c1);
  todoTxt.value = "";
  
  let newLi = document.createElement(`li`);
  newLi.classList.add("todoitem");
  newLi.innerHTML = `<span class="todoitem--subject">${c1.title}</span>
  <span class="todoitem--detail">
    <span class="todoitem--detail__date">${c1.createdAt[0]}</span>
    <span class="todoitem--detail__select">
    <input type="checkbox" onchange="checkboxstatus(this)" value="${c1.id}"/>
    </span>
    <span class="todoitem--detail__delete">
    <img src="./Assets/Img/trash.svg" alt=""/>
    </span>
  </span>`;
  toDoList.appendChild(newLi);
  
  console.log(arr);
});

内容的提问来源于stack exchange,提问作者Yahya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 08:45:32