待办列表删除按钮事件重复触发问题求助
待办列表删除按钮重复触发问题分析与解决
问题原因
你每次点击添加待办项的按钮时,都会通过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
相关产品推荐
相关产品推荐

