click事件监听器仅前两个<li>生效,其余<li>点击触发错误div原因
问题核心原因
错位问题本质是两个逻辑错误共同导致的:
- 类切换逻辑错误:你直接对控制显隐的
.info类做toggle,第一次点击时元素的info类被移除后,就会从document.querySelectorAll(".info")的返回集合中消失,集合长度、元素索引会随着点击动态变化,但你绑定事件时用的循环索引i是固定值,自然会出现索引匹配错位。 - 匹配逻辑脆弱:靠全局索引关联li和对应div的写法本身容错率极低,DOM结构稍作变动就会匹配失败,另外你模板里重复写了相同的
id="info",违反了HTML全局id唯一的规范,也会埋下隐患。
修复方案
不要直接切换基础样式类,新增独立的显隐状态类,同时放弃全局索引匹配的写法,点击时直接定位当前li对应的关联div即可,从根源上避免错位。
修复后代码
HTML模板部分
去掉重复的id,给info元素默认加上隐藏状态类:
<div> {% for workout in workouts %} <ul> <li class="item">{{ workout.name }}</li> {% autoescape false %} <!-- 移除重复id,默认加hidden类实现初始隐藏 --> <div class="info hidden"> <p>{{ workout.description }}</p> </div> {% endautoescape %} </ul> {% endfor %} </div>
CSS部分
把显隐规则绑定到独立的状态类上,保证.info类始终存在,不会从DOM查询集合中丢失:
.info { /* 可在此处添加.info的基础样式,比如内边距、边框、圆角等 */ } .info.hidden { display: none; }
JS部分
放弃预存所有info元素+索引匹配的写法,点击时直接查找当前li所属ul下的info元素,100%匹配不会错位:
const liList = document.querySelectorAll("li.item"); liList.forEach(li => { li.addEventListener("click", function () { // 找当前li最近的父级ul,再找ul下的.info元素,精准对应无错位 const targetInfo = li.closest("ul").querySelector(".info"); targetInfo.classList.toggle("hidden"); }); });
内容的提问来源于stack exchange,提问作者Pedram Yazdani
相关产品推荐
相关产品推荐

