用name分组+change监听可稳定全选/反选逻辑;数据项用name="item",全选框用name="select-all"或无name;需手动设置indeterminate并按checked数量同步状态。

直接用 name 分组 + change 事件监听,就能稳住全选/反选逻辑;靠 class 或遍历所有 input 容易误操作、状态不同步。
怎么用 name 正确分组 checkbox
全选框和数据项必须用不同的 name 值,否则表单提交时会混在一起。比如数据项统一用 name="item",全选框设为 name="select-all" 或干脆不设 name。
- 用
document.querySelectorAll('input[name="item"]')获取目标复选框,比getElementsByClassName更准、返回静态 NodeList - 别用
getElementsByTagName('input')然后靠索引排除——一旦 DOM 结构微调(比如加个搜索框 input),下标就错位 - 如果页面有多个复选框组,每组用独立的
name值(如"user-roles"、"permissions"),避免 query 冲突
indeterminate 状态为什么必须手动设
浏览器不会自动把“部分勾选”映射到全选框的 indeterminate 状态,不手动设,它永远只在 true/false 之间切,视觉上失去语义。
- 更新逻辑:先设
selectAll.indeterminate = false,再根据统计结果设checked,否则旧的indeterminate可能残留 - 统计时遍历所有
name="item"的 checkbox,数checked为true的个数:const checkedCount = items.filter(i => i.checked).length - 若
checkedCount === 0→selectAll.checked = false;若全满 →checked = true;否则 →indeterminate = true
反选功能里最容易翻车的点
反选不是对所有 checkbox 遍历取反,而是只对数据项(即 name="item")操作,全选框自己必须被跳过。
- 错误写法:
items.forEach(i => i.checked = !i.checked)—— 如果items里不小心包含了全选框,它也会被翻转 - 正确做法:明确限定范围,例如
document.querySelectorAll('input[name="item"]'),不依赖父容器或 class - 反选后必须重新触发一次状态校验(同上统计逻辑),否则全选框的
checked和indeterminate会滞后 - 不要用
click()模拟点击来触发反选,容易引发事件循环或重复执行
大量 checkbox(500+)时的性能注意项
原生 querySelectorAll 在 500 个以内没问题,但超过后每次遍历都可能卡顿,尤其在低端设备上。
- 避免在
change回调里反复调用querySelectorAll,应提前缓存节点列表 - checkbox 不支持事件委托(
change不冒泡),但可用click事件捕获 + 判断target.type === 'checkbox'来降频处理 - 真要撑到上千项,建议加防抖(如 100ms 内只响应最后一次操作),或改用虚拟滚动 + 状态 Map 管理
真正难的不是写对那几行 checked = !checked,而是让全选框的视觉状态(checked + indeterminate)始终和数据项的真实勾选分布严格一致——这个同步时机和重置顺序,稍一疏忽就会出 bug。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











