全选/反选需用 javascript 监听 change 事件,通过 element.checked = boolean 同步状态,并动态更新 indeterminate 属性以准确反映部分选中状态。

用 JavaScript 监听全选 checkbox 状态
反选功能不是 HTML 原生支持的,必须靠 JS 控制。关键在于监听那个“全选/反选”复选框(通常叫 selectAll)的 change 事件,而不是 click——因为用户可能用空格键或屏幕阅读器触发状态切换,change 更可靠。
常见错误是直接在 onclick 里写逻辑,结果键盘操作失效;或者没判断 event.target.checked,导致点击后状态和逻辑不一致。
- 给全选 checkbox 设置唯一
id="selectAll"和type="checkbox" - 所有子项 checkbox 统一加 class,比如
class="item-checkbox" - 监听
document.getElementById('selectAll').addEventListener('change', ...)
遍历并设置每个子 checkbox 的 checked 属性
不能用 setAttribute('checked', true) 或 removeAttribute('checked'),这只会修改 HTML 属性,不会同步 DOM 的实际选中状态。必须直接操作 element.checked = boolean。
另外注意:如果子 checkbox 有动态增删,建议每次反选都重新 query,别缓存 NodeList(它可能是 live 的,也可能不是,行为不一致)。
- 用
document.querySelectorAll('.item-checkbox')拿到所有子项 - 循环中写
item.checked = !selectAll.checked,不是= selectAll.checked - 避免用
for...in遍历 NodeList,用for...of或传统for (let i = 0; ...)
同步更新全选 checkbox 的 indeterminate 状态
当部分子项被勾选时,全选框应显示为“半选”状态(短横线),这靠 indeterminate 属性控制。但这个属性只影响视觉,不改变 checked 值,且不能通过 HTML 属性设置,只能 JS 赋值。
容易忽略的是:每次子项变动(包括反选后),都要重新计算全选框状态——否则反选完发现全选框还是半选,或全选了却没变对勾。
- 计算已勾选子项数:
const checkedCount = [...items].filter(i => i.checked).length - 设全选框:
selectAll.checked = checkedCount === items.length - 再设:
selectAll.indeterminate = checkedCount > 0 && checkedCount - 注意顺序:先设
checked,再设indeterminate,否则后者可能被覆盖
绑定子项 change 事件来驱动全选框状态更新
反选只是单向操作,但用户也会手动点子项。如果没监听子项变化,反选后手动取消某一项,全选框还保持勾选,就出错了。
这里有个性能细节:不要给每个子项单独绑事件,用事件委托更稳妥,尤其子项可能异步加载或频繁重绘。
- 监听父容器(如
<div id="list">)的 <code>change事件 - 用
event.target.matches('.item-checkbox')判断是否是目标元素 - 触发后立即调用上面提到的“同步全选框状态”逻辑
- 避免在子项事件里直接改
selectAll.checked,统一走状态计算函数
反选本身几行代码就能写完,真正复杂的是状态同步的闭环:子项变 → 全选框响应;全选框变 → 子项响应;中间还要处理半选、动态节点、可访问性。漏掉任意一环,UI 就会和真实状态脱节。











