表格数据要导出 Excel?做了个纯前端导出工具
后台列表页几乎都有"导出"按钮。要导出成 Excel,第一反应是装 SheetJS,但为了一个导出功能引一个几百 KB 的库,很多场景没必要——尤其是只要单张表、能用 CSV 打开就行的时候。
做了个轻量方案:纯前端拼 CSV 导出,中文不乱码,长数字不被科学计数法吃掉。多 sheet 的场景单独说,那种确实得用库。
一、拼 CSV
function toCSV(rows, headers) {
const esc = (v) => {
const s = String(v ?? '');
return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
};
const head = headers.join(',');
const body = rows.map((r) => headers.map((h) => esc(r[h])).join(',')).join('\r\n');
return '\uFEFF' + head + '\r\n' + body;
}
两个细节:值里有逗号、引号、换行时必须用双引号包裹,内部引号写成两个;行分隔用 \r\n 而不是 \n,Excel 对 \n 的处理有时会出问题。
二、中文乱码要加 BOM
开头那个 \uFEFF 是字节顺序标记。不加的话 Excel 会按系统默认编码(中文 Windows 是 GBK)去解读 UTF-8 的字节,中文全变乱码。加上 BOM,Excel 才知道这是 UTF-8。
这个坑很典型:用记事本或者代码编辑器打开 CSV 正常,用 Excel 打开就乱码,原因就在这里。
三、长数字被转成科学计数法
function escForExcel(v, asText = false) {
const s = String(v ?? '');
if (asText && /^\d{11,}$/.test(s)) return `="${s}"`;
return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
}
订单号、身份证号这种十几位的纯数字,Excel 会自动当成数字处理,超过十一位就显示成 1.23457E+17,双击进去精度已经丢了。写成 ="123456789012345" 这种公式形式,Excel 会当成文本保留原样。
是不是要这样处理取决于字段含义——手机号、订单号要当文本,金额、数量该当数字。所以做成按字段配置,而不是一刀切。
四、下载
function download(filename, content, mime) {
const blob = new Blob([content], { type: mime });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
}
revokeObjectURL 要在点击之后调用,调早了下载会失败。生成的 blob URL 不释放会一直占着内存,批量导出时尤其明显。
五、踩过的坑
第一个坑是中文乱码。 前面说的,加 BOM。
第二个坑是长数字变科学计数法。 前面说的,按字段决定要不要当文本。
第三个坑是逗号和引号没转义。 地址字段里带逗号,不转义会让整行串列。
第四个坑是换行用错。 用 \n 在部分版本的 Excel 里不换行,整份数据挤成一行。用 \r\n。
第五个坑是 blob URL 没释放。 每次导出都生成一个新的 blob URL,不 revoke 会累积。
第六个坑是多 sheet 需求。 CSV 天生只有一张表。要导出多个工作表,要么引 SheetJS 生成真正的 xlsx,要么把 HTML 表格伪装成 .xls——后者打开时 Excel 会弹"格式与扩展名不匹配"的警告,体验不好。所以工具里对多 sheet 明确建议用库,不硬凑。
六、小结
单表导出用 CSV 就够了,几百字节的代码替代一个库。要注意的就三件事:BOM、转义、长数字。真要复杂格式(多 sheet、样式、公式)就别省这个库,硬凑出来的方案用户打开时会看到警告。
后来加了表头别名。导出的列名用中文而不是字段 key,直接给业务看不用再解释,别名配置跟字段一起传。
另外支持数据格式化。日期、金额在导出前先转成字符串,避免 Excel 里显示成奇怪的序列号或者科学计数法。
还有个功能是大数据量分批。几万行一次性拼字符串会让页面卡住,按五千行一批生成再合并,或者干脆提示改用服务端导出。
最后是文件名带时间戳。导出的文件名自动加上日期时间,多次导出不会互相覆盖。
还有个功能是空数据处理。没有数据时导出按钮置灰,或者导出一个只有表头的空文件,看业务需要。另外支持字段顺序:按传入顺序输出,不要按对象 key 的顺序,后者不可控。最后是编码检查:导出前确认没有会破坏 CSV 结构的字符,尤其是来自用户输入的字段。
另外支持选择导出字段,不是所有列都要导出,按需勾选更实用。还有个细节是导出前先预览前几行,确认格式对了再下载完整文件。
还有个细节是支持导出时选择编码,UTF-8 带不带 BOM 按目标系统决定,老版本 Excel 必须要带。另外支持记录导出历史,避免重复导出同样的数据。
还有个细节是导出的文件名不要带特殊字符,斜杠和冒号在某些系统上会导致保存失败,用中横线和下划线代替。
- 点赞
- 收藏
- 关注作者
评论(0)