You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 01:18:21