使用insertAdjacentHTML渲染列表时removeChild()仅对首个子项生效问题
修复列表项删除功能异常问题
问题根源
- 事件绑定错误:每次循环中使用
document.querySelectorAll('.task-item')[0]和document.querySelectorAll('.clear-item')[0]始终获取页面中第一个匹配的元素,导致所有删除点击事件都绑定到了第一个列表项和删除图标上——这就是只有顶部项能删除、其他项无响应的原因。 - 无效DOM操作:第一个项被删除后,绑定的事件仍试图操作已被移除的DOM节点,因此抛出
Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node错误。 - 标签语法错误:代码中
<i>标签存在多余的闭合标签</i>,需修正。
解决方案:推荐使用事件委托(更高效)
事件委托只需给父容器绑定一次事件,即可处理所有子元素的点击,避免重复绑定,同时支持动态新增的列表项。
修改后的代码:
const renderList = (activities) => { const display = document.getElementById('task-list-display'); // 清空容器,避免重复渲染(按需保留) display.innerHTML = ''; activities.forEach((activity) => { display.insertAdjacentHTML('beforeend', ` <li class="task-item"> <div class="chk-descr"> <input data-a1="${activity.index}" type="checkbox" name="completed" class="completed" /> <p data-b1="${activity.index}" class="description" contenteditable="true">${activity.description}</p> </div> <i class="clear-item fa fa-trash" data-index="${activity.index}"></i> </li> `); }); // 事件委托:父容器监听点击,判断是否点击删除按钮 display.addEventListener('click', (e) => { if (e.target.classList.contains('clear-item')) { // 找到当前删除按钮所属的列表项 const listItem = e.target.closest('.task-item'); if (listItem) { // 直接移除列表项 listItem.remove(); // 如需更新数据源activities,可添加以下逻辑: // activities = activities.filter(item => item.index !== parseInt(e.target.dataset.index)); } } }); };
关键改动说明:
- 移除重复的
id="task-item":ID必须唯一,循环生成重复ID不符合规范。 - 修正
<i>标签闭合错误。 - 给删除图标添加
data-index:方便后续关联对应活动项(如需更新数据源)。 - 使用
closest('.task-item'):快速定位删除按钮所属的列表项,无需复杂DOM查询。 - 调用
listItem.remove():直接删除元素自身,比removeChild更简洁可靠。
备选方案:绑定单个项的事件
如果不想用事件委托,可在每次插入列表项后,直接获取刚添加的元素并绑定事件:
const renderList = (activities) => { const display = document.getElementById('task-list-display'); display.innerHTML = ''; activities.forEach((activity) => { display.insertAdjacentHTML('beforeend', ` <li class="task-item"> <div class="chk-descr"> <input data-a1="${activity.index}" type="checkbox" name="completed" class="completed" /> <p data-b1="${activity.index}" class="description" contenteditable="true">${activity.description}</p> </div> <i class="clear-item fa fa-trash"></i> </li> `); // 获取刚插入的最后一个列表项 const listItem = display.lastElementChild; // 在当前列表项内查找删除按钮 const clearItem = listItem.querySelector('.clear-item'); clearItem.addEventListener('click', () => { listItem.remove(); // 如需更新数据源,在此处处理 }); }); };
关键改动说明:
- 使用
display.lastElementChild获取刚插入的列表项,而非查询整个文档的第一个元素。 - 每个删除按钮仅绑定到对应列表项的事件,避免事件绑定混乱。
内容的提问来源于stack exchange,提问作者German
相关产品推荐
相关产品推荐

