导出CSV必须结构化提取表格数据并严格遵循RFC 4180规范:逐单元格取textContent、双引号包裹所有字段、内部双引号转义为""、换行符保留且用\r\n、内容开头加\uFEFF BOM、MIME类型设为"text/csv"、下载后及时revokeObjectURL。

导出表格前先提取 table 数据,别直接读 HTML 字符串
直接用 innerHTML 或 outerHTML 拿 <table> 内容再正则清洗,容易被嵌套标签、换行、引号、逗号搞崩。CSV 格式对字段分隔和换行敏感,必须结构化提取。
正确做法是遍历 rows 和 cells,逐单元格取 textContent(不是 innerText,后者受 CSS 影响),再手动转义:
- 每个字段用双引号包裹(即使不含逗号,也统一处理)
- 字段内若含双引号,需替换成两个双引号
""(CSV RFC 4180 规范) - 字段内若含换行符
\n,保留它,但必须在双引号内
用 Blob 构造 CSV 内容时注意 MIME 类型和换行符
Blob 的 type 参数写成 "text/csv;charset=utf-8" 是常见错误——浏览器实际不校验 charset,但某些旧版 Excel 会误判编码。更稳妥的是用 "text/csv",并在内容开头加 UTF-8 BOM:\uFEFF。
换行必须用 \r\n(Windows 风格),哪怕你开发环境是 macOS/Linux。Excel 在 Windows 和 macOS 上都依赖 \r\n 识别行,仅用 \n 会导致所有数据挤在第一行。
立即学习“前端免费学习笔记(深入)”;
示例关键片段:
const csvContent = "\uFEFF" + rows.map(row =>
row.map(cell => `"${cell.replace(/"/g, '""')}"`).join(",")
).join("\r\n");<br>const blob = new Blob([csvContent], { type: "text/csv" });
触发下载用 URL.createObjectURL,别漏掉 revoke
生成 blobUrl 后通过 <a href="..." download="data.csv"> 下载是主流做法,但有两点易错:
-
download属性在 iOS Safari 和部分微信内置浏览器中无效(会打开而非下载),此时只能提示用户“长按链接保存” - 每次调用
createObjectURL都会占用内存,必须在click事件后尽快调用URL.revokeObjectURL(blobUrl),否则可能引发内存泄漏(尤其高频导出场景)
推荐封装成可复用函数:
function downloadCSV(csvContent, filename = "data.csv") {<br> const blob = new Blob(["\uFEFF" + csvContent], { type: "text/csv" });<br> const url = URL.createObjectURL(blob);<br> const a = document.createElement("a");<br> a.href = url;<br> a.download = filename;<br> document.body.appendChild(a);<br> a.click();<br> document.body.removeChild(a);<br> URL.revokeObjectURL(url);<br>}
表头含中文或特殊字符时,BOM 和引号缺一不可
没加 \uFEFF BOM,Excel 打开中文表头大概率显示乱码(显示为 “涓枃” 这类),而仅加 BOM 不加双引号包裹,遇到含逗号的中文字段(如 “张三,工程师”)就会被 Excel 拆成两列。
所以这两步必须同时存在:
- CSV 字符串开头加
\uFEFF - 每一列值都用双引号包裹,并正确转义内部双引号
如果表格用了 colspan 或 rowspan,CSV 无法表达合并逻辑,只能按单元格位置平铺——这是格式本质限制,不是代码能绕过的。



















