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

如何使用JS、jQuery从带row/col span的表格选行生成新表格

解决方案

核心思路

  • 先解析源表格所有单元格的实际覆盖范围(起始行、结束行、起始列、结束列),解决跨行跨列单元格的定位问题
  • 收集用户选中的行索引集合
  • 基于选中行集合重新计算每个保留单元格的跨行数值,过滤完全不在选中行范围内的单元格
  • 按顺序构建新表格,避免重复添加跨行单元格

完整实现代码

// 解析表格单元格的实际覆盖范围
function parseTableCells($table) {
  const cellInfos = [];
  const $rows = $table.find('tbody tr');
  const rowCount = $rows.length;
  const colCount = $rows.first().find('td, th').length;
  // 初始化占用标记矩阵
  const occupied = Array.from({length: rowCount}, () => Array(colCount).fill(false));

  $rows.each(function(rowIdx) {
    const $cells = $(this).find('td, th');
    let colIdx = 0;
    $cells.each(function() {
      // 跳过已经被前面跨行/跨列单元格占用的位置
      while (colIdx < colCount && occupied[rowIdx][colIdx]) {
        colIdx++;
      }
      if (colIdx >= colCount) return false;

      const $cell = $(this);
      const rowSpan = parseInt($cell.attr('rowspan')) || 1;
      const colSpan = parseInt($cell.attr('colspan')) || 1;
      const endRow = rowIdx + rowSpan - 1;
      const endCol = colIdx + colSpan - 1;

      // 标记占用范围
      for (let r = rowIdx; r <= endRow; r++) {
        for (let c = colIdx; c <= endCol; c++) {
          occupied[r][c] = true;
        }
      }

      cellInfos.push({
        $cell: $cell.clone(),
        startRow: rowIdx,
        endRow: endRow,
        startCol: colIdx,
        endCol: endCol,
        originRowSpan: rowSpan,
        originColSpan: colSpan
      });
      colIdx += colSpan;
    });
  });
  return {cellInfos, rowCount, colCount};
}

// 基于选中行生成新表格
function generateNewTable($sourceTable) {
  const {cellInfos, colCount} = parseTableCells($sourceTable);
  // 收集选中的行索引(tbody内的行索引,从0开始)
  const selectedRows = $sourceTable.find('tbody input[type="checkbox"]:checked')
    .closest('tr')
    .map(function() { return $(this).index(); })
    .get()
    .sort((a,b) => a - b); // 按行顺序排序

  if (selectedRows.length === 0) return null;

  // 预计算每个选中行的映射索引
  const selectedRowSet = new Set(selectedRows);
  const rowIndexMap = new Map();
  selectedRows.forEach((r, idx) => rowIndexMap.set(r, idx));

  // 初始化新表格的占用矩阵
  const newRowCount = selectedRows.length;
  const newOccupied = Array.from({length: newRowCount}, () => Array(colCount).fill(false));
  const $newTbody = $('<tbody></tbody>');

  // 逐行构建新表格
  selectedRows.forEach((originalRow, newRowIdx) => {
    const $newRow = $('<tr></tr>');
    for (let colIdx = 0; colIdx < colCount; colIdx++) {
      if (newOccupied[newRowIdx][colIdx]) continue;

      // 找到当前位置对应的源单元格
      const cellInfo = cellInfos.find(info => 
        info.startRow <= originalRow && info.endRow >= originalRow &&
        info.startCol <= colIdx && info.endCol >= colIdx
      );
      if (!cellInfo) continue;

      // 计算新的rowspan:统计源单元格覆盖的行中属于选中行的数量
      let newRowSpan = 0;
      for (let r = cellInfo.startRow; r <= cellInfo.endRow; r++) {
        if (selectedRowSet.has(r)) newRowSpan++;
      }
      if (newRowSpan <= 0) continue;

      // 创建新单元格
      const $newCell = cellInfo.$cell.clone();
      $newCell.attr('rowspan', newRowSpan > 1 ? newRowSpan : null); // 不需要跨的话删掉属性
      $newCell.attr('colspan', cellInfo.originColSpan > 1 ? cellInfo.originColSpan : null);

      // 标记新表格的占用范围
      for (let r = newRowIdx; r < newRowIdx + newRowSpan; r++) {
        for (let c = cellInfo.startCol; c <= cellInfo.endCol; c++) {
          newOccupied[r][c] = true;
        }
      }

      $newRow.append($newCell);
    }
    $newTbody.append($newRow);
  });

  // 构建完整新表格,复制表头和样式
  const $newTable = $('<table></table>').attr('class', $sourceTable.attr('class'));
  $newTable.append($sourceTable.find('thead').clone());
  $newTable.append($newTbody);
  return $newTable;
}

使用示例

<!-- 源表格结构示例 -->
<table id="sourceTable" border="1" cellpadding="8" cellspacing="0">
  <thead>
    <tr>
      <th>选择</th>
      <th>列1</th>
      <th>列2</th>
      <th>列3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><input type="checkbox"></td>
      <td rowspan="3">A</td>
      <td>B1</td>
      <td>C1</td>
    </tr>
    <tr>
      <td><input type="checkbox"></td>
      <td>B2</td>
      <td>C2</td>
    </tr>
    <tr>
      <td><input type="checkbox"></td>
      <td>B3</td>
      <td>C3</td>
    </tr>
    <tr>
      <td><input type="checkbox"></td>
      <td>D</td>
      <td colspan="2">E</td>
    </tr>
    <tr>
      <td><input type="checkbox"></td>
      <td>F</td>
      <td>G</td>
      <td>H</td>
    </tr>
  </tbody>
</table>
<br>
<button id="generateBtn">生成新表格</button>
<br><br>
<div id="resultContainer"></div>

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
// 绑定生成事件
$('#generateBtn').click(function() {
  const $newTable = generateNewTable($('#sourceTable'));
  $('#resultContainer').empty().append($newTable || '<p>请先选择行</p>');
});
</script>

兼容性说明

  • 支持任意行列合并的表格结构,自动计算合并范围
  • 保留原表格的样式、单元格内容和属性
  • 自动处理选中行的顺序,生成的表格和源表格行顺序一致

内容的提问来源于stack exchange,提问作者Praveen Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 17:36:00