頁面存在多個獨立 <table>,每個表格表頭有「全選」 Checkbox,tbody 每行有子 Checkbox。傳統寫法為每個表格寫獨立 ID、綁定獨立事件,代碼冗余、難維護。
name="checkAll"。name="itemGroup{N}"(或 data-group="N")。data-target="itemGroup{N}" 指明控制哪組。<table class="data-table">
<thead>
<tr><th><input type="checkbox" name="checkAll" data-target="items1"> 全選</th>...</tr>
</thead>
<tbody>
<tr><td><input type="checkbox" name="items1" value="1"></td>...</tr>
...
</tbody>
</table>
<table class="data-table">
<thead>
<tr><th><input type="checkbox" name="checkAll" data-target="items2"> 全選</th>...</tr>
</thead>
<tbody>
<tr><td><input type="checkbox" name="items2" value="1"></td>...</tr>
</tbody>
</table>
// 事件委託:綁在 document 或共同祖先
document.addEventListener('change', e => {
const target = e.target;
if (!target.matches('input[type="checkbox"]')) return;
// 1. 全選 Checkbox 觸發
if (target.name === 'checkAll') {
const groupName = target.dataset.target; // 如 "items1"
const items = document.querySelectorAll(`input[name="${groupName}"]`);
items.forEach(item => item.checked = target.checked);
return;
}
// 2. 子 Checkbox 觸發 → 更新對應全選狀態
const groupName = target.name; // 如 "items1"
const allItems = document.querySelectorAll(`input[name="${groupName}"]`);
const checkedItems = document.querySelectorAll(`input[name="${groupName}"]:checked`);
const checkAll = document.querySelector(`input[name="checkAll"][data-target="${groupName}"]`);
if (checkAll) {
checkAll.checked = allItems.length === checkedItems.length;
checkAll.indeterminate = checkedItems.length > 0 && checkedItems.length < allItems.length;
}
});
function getAllCheckedValues() {
const result = {};
document.querySelectorAll('input[name^="items"]:checked').forEach(cb => {
const group = cb.name;
if (!result[group]) result[group] = [];
result[group].push(cb.value);
});
return result; // { items1: ["1","3"], items2: ["2"] }
}
indeterminate 狀態自動維護,UX 專業。table.data-table > tbody input[name="..."]。querySelectorAll 可能卡頓,考慮維护 Map<groupName, HTMLInputElement[]> 緩存引用。用「約定優於配置」的命名規約 + 單一事件委託,輕鬆搞定任意數量表格的全選交互。