
本文详解如何正确遍历含嵌套 的 HTML 表格结构,递归提取所有有效数据行(跳过 colspan 占位行和空嵌套容器),生成格式规范、行列对齐的 CSV 文件。
本文详解如何正确遍历含嵌套 `
| ,递归进入其 | 提取子行; 所在行(它们本身不承载数据,仅作容器); ❌ 忽略无 |
或 | 数量不匹配的无效行。 以下为健壮、可复用的实现方案: /**
* 从 DOM 表格中提取所有扁平化数据行(支持嵌套 table)
* @param {HTMLTableElement} table - 根表格元素
* @returns {string[][]} 二维数组,每项为一行的字符串值数组
*/
function extractTableData(table) {
const headers = Array.from(table.querySelectorAll('thead th'))
.map(th => th.textContent.trim());
const rows = [];
// 递归处理指定节点下的所有 tbody > tr
function collectRows(context) {
const tbodyElements = context.querySelectorAll('tbody');
tbodyElements.forEach(tbody => {
tbody.querySelectorAll('tr').forEach(tr => {
// 跳过包含 colspan 占位单元格的行(它们不是数据行)
const hasColspanCell = tr.querySelector('td[colspan], th[colspan]');
if (hasColspanCell) {
// 递归提取该单元格内嵌套的 table 数据
const nestedTables = tr.querySelectorAll('td table, th table');
nestedTables.forEach(nestedTable => {
collectRows(nestedTable);
});
return;
}
// 提取当前行的有效 td/th 文本
const cells = Array.from(tr.querySelectorAll('td, th'))
.map(cell => cell.textContent.trim());
// 仅保留列数与 header 匹配的行(确保结构一致)
if (cells.length === headers.length && cells.some(cell => cell !== '')) {
rows.push(cells);
}
});
});
}
collectRows(table);
return [headers, ...rows];
}
/**
* 将二维数组转换为 CSV 字符串(自动转义含逗号/换行/引号的字段)
* @param {string[][]} data - 行数据二维数组
* @returns {string} CSV 格式字符串
*/
function arrayToCsv(data) {
return data.map(row =>
row.map(cell => {
// 若字段含逗号、双引号或换行符,用双引号包裹,并将内部双引号转义为两个双引号
if (/[,\"\n\r]/.test(cell)) {
return `"${cell.replace(/"/g, '""')}"`;
}
return cell;
}).join(',')
).join('\n');
}
/**
* 触发 CSV 文件下载
* @param {string} csvContent - CSV 字符串
* @param {string} filename - 下载文件名(默认 GfG.csv)
*/
function downloadCsv(csvContent, filename = 'GfG.csv') {
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url); // 清理内存
}
// 使用示例
function exportToCsv() {
const table = document.querySelector('table');
if (!table) return;
try {
const data = extractTableData(table);
const csv = arrayToCsv(data);
console.log('Generated CSV:\n', csv);
downloadCsv(csv);
} catch (err) {
console.error('CSV export failed:', err);
}
}
|

















