如何使用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
相关产品推荐
相关产品推荐

