如何实现HTML表格每行每列仅允许单选一个带data属性的div元素
问题背景
现有3行3列的HTML表格,每个单元格内包含可点击的div元素:
<table border="1" cellpadding="5" class="test"> <tr> <td class="talent-cell"><div class="btn7" data-value="0">aaa</div></td> <td class="talent-cell"><div class="btn8" data-value="1">bbb</div></td> <td class="talent-cell"><div class="btn9" data-value="2">ccc</div></td> </tr> <tr> <td class="talent-cell"><div class="btn7" data-value="0">ddd</div></td> <td class="talent-cell"><div class="btn8" data-value="1">eee</div></td> <td class="talent-cell"><div class="btn9" data-value="2">fff</div></td> </tr> <tr> <td class="talent-cell"><div class="btn7" data-value="0">ggg</div></td> <td class="talent-cell"><div class="btn8" data-value="1">hhh</div></td> <td class="talent-cell"><div class="btn9" data-value="2">iii</div></td> </tr> </table>
原有功能已经实现:点击div时获取data-value属性值,通过URLSearchParams拼接查询字符串更新地址栏。
现在需要新增互斥选择规则:表格的每一行、每一列中最多只能选中1个div元素。
原有实现代码存在逻辑冗余,且仅做了同列按钮的不完整互斥,未处理行、列交叉的互斥判断:
var btn7; var btn8; var btn9; $('.btn7').click(function () { if ($(this).attr('data-selected') === 'true') { $(this).attr('data-selected', 'false'); $(this).removeClass('selected'); } else { $(this).closest('tr').find('.btn7').not(this) .removeClass('selected').attr('data-selected', 'false'); $(this).attr('data-selected', 'true'); $(this).addClass('selected'); params.set('var7', $(this).data("value")); window.history.replaceState({}, '', `?${params}`); } }); $('.btn8').click(function () { if ($(this).attr('data-selected') === 'true') { $(this).attr('data-selected', 'false'); $(this).removeClass('selected'); } else { $(this).closest('tr').find('.btn8').not(this) .removeClass('selected').attr('data-selected', 'false'); $(this).attr('data-selected', 'true'); $(this).addClass('selected'); params.set('var8', $(this).data("value")); window.history.replaceState({}, '', `?${params}`); } }); $('.btn9').click(function () { if ($(this).attr('data-selected') === 'true') { $(this).attr('data-selected', 'false'); $(this).removeClass('selected'); } else { $(this).closest('tr').find('.btn9').not(this) .removeClass('selected').attr('data-selected', 'false'); $(this).attr('data-selected', 'true'); $(this).addClass('selected'); params.set('var9', $(this).data("value")); window.history.replaceState({}, '', `?${params}`); } }); const params = new URLSearchParams({ var7: btn7, var8: btn8, var9: btn9, });
实现方案
直接合并冗余的事件绑定逻辑,在选中元素前增加行、列两层互斥清理即可,原有功能逻辑完全保留:
// 初始化查询参数对象 const params = new URLSearchParams(); // 统一绑定所有单元格内的可点击按钮,无需按列分开绑定 $('.talent-cell > div').click(function () { const $current = $(this); const isSelected = $current.attr('data-selected') === 'true'; // 定位当前元素所在行 const $currentRow = $current.closest('tr'); // 获取当前元素所在列索引 const colIndex = $current.closest('td').index(); // 自动匹配当前按钮对应的查询参数名:btn7 -> var7 const paramName = $current.attr('class').match(/btn\d+/)[0].replace('btn', 'var'); if (isSelected) { // 点击已选中的按钮,取消选中并删除对应参数 $current.attr('data-selected', 'false').removeClass('selected'); params.delete(paramName); } else { // 1. 清除同一行所有已选中的按钮 $currentRow.find('div[data-selected="true"]').each(function () { const $canceled = $(this); const canceledParam = $canceled.attr('class').match(/btn\d+/)[0].replace('btn', 'var'); $canceled.attr('data-selected', 'false').removeClass('selected'); params.delete(canceledParam); }); // 2. 清除同一列所有已选中的按钮 $('.test tr').each(function () { const $colBtn = $(this).find('td').eq(colIndex).find('div[data-selected="true"]'); if ($colBtn.length) { const canceledParam = $colBtn.attr('class').match(/btn\d+/)[0].replace('btn', 'var'); $colBtn.attr('data-selected', 'false').removeClass('selected'); params.delete(canceledParam); } }); // 3. 选中当前按钮,写入对应参数 $current.attr('data-selected', 'true').addClass('selected'); params.set(paramName, $current.data("value")); } // 更新地址栏查询字符串 window.history.replaceState({}, '', `?${params}`); });
逻辑说明
- 去掉了原代码中重复的三个事件绑定,统一处理所有按钮的点击逻辑,后续增减行列不需要新增重复代码
- 选中新元素前先做两层互斥校验:
- 遍历当前行所有已选中的元素,全部取消选中状态并删除对应的查询参数
- 根据列索引遍历所有行,找到同列已选中的元素,全部取消选中状态并删除对应的查询参数
- 自动根据按钮class映射对应的查询参数key,不需要硬编码每个按钮对应的参数名
- 完全保留原有点击已选中元素取消选中、自动更新地址栏的功能
内容的提问来源于stack exchange,提问作者Keroster
相关产品推荐
相关产品推荐

