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

Todo App删除功能异常:仅首个Todo正常删除,其余批量删除

Todo App 删除功能异常问题修复

问题现象

开发的Todo App中删除功能异常:仅首个Todo可正常删除,点击其他Todo的删除按钮会批量删除多个Todo。期望点击删除按钮仅移除对应Todo元素及数据,但实际出现批量删除情况,尝试过splice方法和delete关键字均无法解决。

问题根源

问题出在表单提交事件的循环逻辑:

  1. 每次添加新Todo时遍历整个todoList数组,给同一个deleteButton和editButton重复绑定点击事件,导致点击一次触发多次删除操作
  2. 循环变量i因闭包特性,最终所有点击事件都引用循环结束时的i值(数组最后一个元素的索引),导致点击任意删除按钮都会删除最后一个Todo
  3. 循环中反复将同一个newTodo元素添加到DOM,造成DOM元素被移动而非创建新元素,进一步加剧问题

修复方案

移除遍历todoList的循环,每次提交表单只创建并添加当前新Todo元素,直接使用最新Todo数据绑定事件避免闭包陷阱;同时优化模态框事件绑定,避免重复绑定。

修复后的JavaScript代码

const todoForm = document.querySelector(".todo-form");
const todos = document.querySelector(".todos");
const todoTitle = document.querySelector(".todo-title");
const modal = document.querySelector("#modal");
const modalClose = document.querySelector(".close-button");
const editedText = document.querySelector(".edited-text ");
const submitEdit = document.querySelector(".submit");

const todoList = [];
let totalTodo = 0;
let currentEditElement = null; // 存储当前编辑的元素

function findFromArray(id, array) {
  for (let i = 0; i < array.length; i++) {
    if (id === array[i].id) {
      return { item: array[i], index: i }; // 返回元素和索引,避免二次查找
    }
  }
  return null;
}

function deleteTodo(id) {
  const element = document.getElementById(id);
  element.remove();
  const data = findFromArray(id, todoList);
  if (data) {
    todoList.splice(data.index, 1);
  }
}

function editTodo(element) {
  currentEditElement = element;
  editedText.value = element.innerText; // 填充当前文本到输入框
  modal.showModal();
}

// 仅绑定一次模态框事件,避免重复绑定
modalClose.addEventListener("click", () => {
  modal.close();
});

submitEdit.addEventListener("click", () => {
  if (currentEditElement) {
    const newTodoText = editedText.value.trim();
    if (newTodoText) {
      currentEditElement.innerText = newTodoText;
      // 更新数组中的数据
      const todoId = currentEditElement.parentElement.id;
      const data = findFromArray(todoId, todoList);
      if (data) {
        data.item.title = newTodoText;
      }
    }
    modal.close();
  }
});

todoForm.addEventListener("submit", (e) => {
  e.preventDefault();
  const title = todoTitle.value.trim();
  if (!title) return; // 空内容不添加

  const newTodo = document.createElement("div");
  const h1 = document.createElement("h1");
  const deleteButton = document.createElement("button");
  const editButton = document.createElement("button");

  deleteButton.innerText = "Delete";
  editButton.innerText = "Edit";

  // 创建当前Todo的数据
  const todoId = "Todo" + totalTodo;
  const newTodoData = {
    id: todoId,
    title,
  };
  todoList.push(newTodoData);
  totalTodo++;

  // 设置当前Todo的DOM属性
  newTodo.classList.add("todo-card");
  newTodo.id = todoId;
  h1.innerText = title;

  // 绑定当前Todo的事件,直接使用当前todoId规避闭包问题
  deleteButton.addEventListener("click", () => deleteTodo(todoId));
  editButton.addEventListener("click", () => editTodo(h1));

  // 组装DOM元素并添加到页面
  newTodo.appendChild(h1);
  newTodo.appendChild(deleteButton);
  newTodo.appendChild(editButton);
  todos.appendChild(newTodo);

  todoTitle.value = "";
});

HTML代码(无需修改)

<body>
  <h1 class="todo-heading">Todo App</h1>
  <form class="todo-form">
    <input class="todo-title" type="text" placeholder="Todo Name" />

    <input type="Submit" class="todo-button" />
  </form>
  <br />
  <div class="todos"></div>
  <dialog id="modal">
    <h1>Edit</h1>
    <input type="text" class="edited-text" placeholder="New Todo" />
    <br />
    <br />
    <button class="submit">Submit</button>
    <button class="close-button">
        <svg class="svg-icon" viewBox="0 0 20 20">
          <path
            d="M10.185,1.417c-4.741,0-8.583,3.842-8.583,8.583c0,4.74,3.842,8.582,8.583,8.582S18.768,14.74,18.768,10C18.768,5.259,14.926,1.417,10.185,1.417 M10.185,17.68c-4.235,0-7.679-3.445-7.679-7.68c0-4.235,3.444-7.679,7.679-7.679S17.864,5.765,17.864,10C17.864,14.234,14.42,17.68,10.185,17.68 M10.824,10l2.842-2.844c0.178-0.176,0.178-0.46,0-0.637c-0.177-0.178-0.461-0.178-0.637,0l-2.844,2.841L7.341,6.52c-0.176-0.178-0.46-0.178-0.637,0c-0.178,0.176-0.178,0.461,0,0.637L9.546,10l-2.841,2.844c-0.178,0.176-0.178,0.461,0,0.637c0.178,0.178,0.459,0.178,0.637,0l2.844-2.841l2.844,2.841c0.178,0.178,0.459,0.178,0.637,0c0.178-0.176,0.178-0.461,0-0.637L10.824,10z"
          ></path>
        </svg>
      </button>
  </dialog>
</body>

关键修复点

  • 移除表单提交事件中的todoList循环,每次仅创建当前新Todo的DOM元素,避免重复绑定事件和DOM元素重复添加
  • 直接使用当前创建的todoId绑定删除事件,规避闭包导致的变量引用问题
  • 将模态框的关闭和提交事件改为仅绑定一次,避免重复绑定导致多次触发
  • 添加currentEditElement变量存储当前编辑元素,优化编辑逻辑
  • 优化findFromArray函数,同时返回元素和索引,减少数组查找次数
  • 添加空内容判断,避免创建空Todo

内容的提问来源于Stack Exchange,提问作者Bidhan chandro sana

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 23:20:38