Todo App删除功能异常:仅首个Todo正常删除,其余批量删除
Todo App 删除功能异常问题修复
问题现象
开发的Todo App中删除功能异常:仅首个Todo可正常删除,点击其他Todo的删除按钮会批量删除多个Todo。期望点击删除按钮仅移除对应Todo元素及数据,但实际出现批量删除情况,尝试过splice方法和delete关键字均无法解决。
问题根源
问题出在表单提交事件的循环逻辑:
- 每次添加新Todo时遍历整个
todoList数组,给同一个deleteButton和editButton重复绑定点击事件,导致点击一次触发多次删除操作 - 循环变量
i因闭包特性,最终所有点击事件都引用循环结束时的i值(数组最后一个元素的索引),导致点击任意删除按钮都会删除最后一个Todo - 循环中反复将同一个
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
相关产品推荐
相关产品推荐

