为什么点击事件监听器仅生效一次?如何实现点击任意li元素执行函数
问题核心原因
你的代码存在两处逻辑错误,直接导致点击事件无法对所有li生效:
- HTML规范明确要求页面内的id值必须全局唯一,你给三个
<li>标签都设置了相同的id="listItem",而document.getElementById()只会返回文档中第一个匹配该id的元素(也就是内容为"One"的li),剩余两个li完全未被获取,自然也无法绑定点击事件。
你原有代码中的CSS规则ul li {cursor: pointer;}没有问题,所有li都会显示可点击的手型鼠标样式,这也容易造成“事件已经绑定但只生效一次”的错觉——实际只有第一个li能响应点击,其余两个li点击无任何反馈。 - 事件回调逻辑写死了操作目标:就算能正确获取所有li元素,当前
clickTodo函数内部直接修改listItem变量指向的固定元素样式,不会响应实际被点击的节点,即便给多个元素绑定了事件,所有点击触发后只会修改第一个li的样式。
可落地的实现方法
要实现任意li被点击时都能触发指定函数,有两种成熟的实现方式:
- 批量绑定独立监听器
首先修正重复id的违规问题,给所有li设置统一的class标识,再通过批量选择器获取所有li,遍历绑定事件,回调中通过当前触发事件的节点操作样式:- 调整后的HTML代码
<ul> <li class="todo-item">One</li> <li class="todo-item">Two</li> <li class="todo-item">Other</li> </ul> - 调整后的JS代码
// 批量获取所有li元素 const listItems = document.querySelectorAll(".todo-item"); // 遍历每个元素绑定点击事件 listItems.forEach(item => { item.addEventListener("click", clickTodo) }) function clickTodo() { // this 指向当前被点击的触发元素 this.style.color = "red" }
- 调整后的HTML代码
- 事件委托实现(适合动态列表场景)
不需要给每个li单独绑定事件,将监听器挂载在父级ul上,利用事件冒泡机制判断点击目标,性能更高,也不会因为后续动态新增li丢失绑定效果:const todoList = document.querySelector("ul"); todoList.addEventListener("click", (e) => { // 判断当前点击的目标是否为li元素 if (e.target.tagName === "LI") { e.target.style.color = "red" } })
内容的提问来源于stack exchange,提问作者user13101974
相关产品推荐
相关产品推荐

