用 document.queryselectorall('table tr') 提取行最稳,转数组后跳过首行表头,逐单元格用 textcontent.trim() 取值并清洗空白与实体,按列索引对齐字段名与值生成 json。

用 document.querySelectorAll('table tr') 提取行最稳
直接遍历 tr 元素,比递归遍历整个 DOM 树快且不易出错。表头通常在第一行,数据从第二行开始——这个规律绝大多数静态报表页都成立,别硬套复杂 selector。
- 用
Array.from(document.querySelectorAll('table tr'))转成数组,方便后续filter和map - 跳过表头:用
rows.filter((_, i) => i > 0),比写:not(thead tr)更可靠(有些表格没thead) - 遇到空行或含
colspan/rowspan的单元格,cells[i]可能为undefined,访问前必须加if (cells[i])判断
textContent.trim() 是唯一安全的取值方式
innerText 在 Safari 里会吞掉不可见空白、合并换行;innerHTML 带标签、有 XSS 风险;jQuery.text() 多一层依赖还慢。真实项目里,只要单元格里没 script 或 iframe,textContent 就够用。
- 每个
td或th都调用.textContent.trim(),别省这一步——全角空格、、换行符都会残留 - 对特殊字符做轻量清洗:
.replace(/[\r\n\t]+/g, ' ').replace(/\u00a0/g, ' ').trim(),比全局正则/\s+/g更准 - 如果某列是数字(如 ID、金额),再额外套一层
parseFloat(),但务必isNaN(val) ? null : val,否则 “—” 或 “N/A” 会变成NaN
字段名和值靠列索引对齐,别信 data-key 或 class
给每个 td 加 data-field="name" 看似灵活,实际维护成本爆炸:改个 HTML 表头顺序,JS 就得同步改;多人协作时极易漏掉。真实后台报表结构稳定,列顺序就是契约。
- 先单独提取表头:
Array.from(table.querySelectorAll('thead th, tr:first-child th, tr:first-child td')).map(el => el.textContent.trim()) - 遍历数据行时,用
headers[i]作 key,cells[i]?.textContent.trim()作 value,严格按位置一一对应 - 操作列(如删/编辑按钮)不参与 JSON 输出:提取表头时提前
headers.filter(h => h !== '操作'),或数据行中跳过最后一列
生成 JSON 前必须处理三类陷阱
表格内容常混入不可见字符、HTML 实体、甚至意外嵌入的脚本片段。直接 JSON.stringify() 很可能在后端解析失败,或触发安全拦截。
- emoji、中文标点、零宽空格(
\u200b)等 Unicode 字符保留没问题,但换行符、制表符必须清理 - 遇到
>、这类实体,用简单映射替换:<code>val.replace(/>/g, '>').replace(/, ',别上 <code>DOMParser——太重且有执行风险 - 空单元格返回空字符串,但后端通常要
null:统一转成val === '' ? null : val,别留空串
表格结构越简单,转换越可靠;一旦出现嵌套表格、跨行单元格、动态渲染内容,就该考虑用后端解析或专用库(如 SheetJS 处理 Excel 导出的 HTML)。前端手动转 JSON 的边界很清晰:固定列数、无交互、纯展示型报表。超出这个范围,硬写 JS 只会增加 debug 成本。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











