本文详解如何通过事件委托机制,为所有(包括后续动态添加的)li 元素绑定点击事件并应用 .done 样式,解决直接 queryselector("li") 仅作用于首个元素的问题。
本文详解如何通过事件委托机制,为所有(包括后续动态添加的)li 元素绑定点击事件并应用 .done 样式,解决直接 queryselector("li") 仅作用于首个元素的问题。
在 JavaScript 中,为多个
正确做法是采用 事件委托(Event Delegation):将事件监听器绑定到静态父容器(如
- ),利用事件冒泡机制捕获子元素的点击,并精准定位目标
- 。
✅ 正确实现方式(事件委托)
const button = document.getElementById("enter"); const input = document.getElementById("userinput"); const ul = document.querySelector("ul"); function inputLength() { return input.value.length; } function createListElement() { const li = document.createElement("li"); li.textContent = input.value.trim(); // 推荐用 textContent 替代 createTextNode ul.appendChild(li); input.value = ""; } function addListAfterClick() { if (inputLength() > 0) createListElement(); } function addListAfterKeydown(event) { if (inputLength() > 0 && event.key === "Enter") createListElement(); } button.addEventListener("click", addListAfterClick); input.addEventListener("keydown", addListAfterKeydown); // ✅ 关键:为 ul 绑定点击事件,委托处理所有 li ul.addEventListener("click", function (e) { const clickedLi = e.target.closest("li"); if (clickedLi) { clickedLi.classList.toggle("done"); // 使用 toggle 更符合用户预期(可取消) } });? 对应 CSS(确保生效)
.done { text-decoration: line-through; color: #666; opacity: 0.8; }⚠️ 注意事项与最佳实践
- 不要重复查询 li:querySelector("li") 每次只返回第一个匹配项;querySelectorAll("li") 虽可获取全部,但无法自动绑定新添加的元素。
- .closest("li") 是核心:它从点击目标(e.target)向上查找最近的
- 祖先(含自身),完美兼容嵌套文本、图标等子内容的点击。
- 推荐 .toggle() 而非 .add():使点击可逆(再次点击取消删除线),提升用户体验。
-
确保 HTML 结构合理:
- 必须存在且是
- 的直接/间接父级,否则事件委托失效。
- 性能更优:仅需一个事件监听器,而非为每个
- 单独绑定,尤其适合大量列表项场景。
通过事件委托,你无需关心
- 是初始渲染还是动态插入——只要它们位于 ul 内,点击即响应。这是现代 DOM 操作中处理动态内容的标准、高效且可维护的方案。

















