前端导出 Excel / PDF
场景
管理后台需要导出报表,数据量可能达到几万行,要求不卡顿、格式美观。
方案设计
导出 Excel(SheetJS)
export-excel.ts
import * as XLSX from 'xlsx';
interface ExportOptions {
data: Record<string, unknown>[];
headers: { key: string; title: string }[];
filename?: string;
sheetName?: string;
}
function exportExcel({ data, headers, filename = 'export', sheetName = 'Sheet1' }: ExportOptions) {
// 1. 构造表头 + 数据行
const headerRow = headers.map((h) => h.title);
const rows = data.map((item) => headers.map((h) => item[h.key]));
// 2. 创建工作表
const ws = XLSX.utils.aoa_to_sheet([headerRow, ...rows]);
// 3. 设置列宽
ws['!cols'] = headers.map(() => ({ wch: 20 }));
// 4. 创建工作簿并下载
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, sheetName);
XLSX.writeFile(wb, `${filename}.xlsx`);
}
导出 PDF(jsPDF)
export-pdf.ts
import jsPDF from 'jspdf';
import autoTable from 'jspdf-autotable';
function exportPDF(
headers: string[],
rows: string[][],
filename = 'export'
) {
const doc = new jsPDF();
autoTable(doc, {
head: [headers],
body: rows,
styles: { font: 'helvetica', fontSize: 10 },
});
doc.save(`${filename}.pdf`);
}
大数据量优化:Web Worker + 流式处理
export-worker.ts
// 主线程
const worker = new Worker(new URL('./excel.worker.ts', import.meta.url));
worker.postMessage({ data, headers });
worker.onmessage = (e: MessageEvent<ArrayBuffer>) => {
const blob = new Blob([e.data], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'export.xlsx';
a.click();
URL.revokeObjectURL(url);
};
excel.worker.ts
import * as XLSX from 'xlsx';
self.onmessage = (e) => {
const { data, headers } = e.data;
const ws = XLSX.utils.json_to_sheet(data, { header: headers });
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
const buffer = XLSX.write(wb, { type: 'array', bookType: 'xlsx' });
self.postMessage(buffer, [buffer]); // Transferable
};
更大数据量
超过 10 万行时,建议由后端生成文件并返回下载链接,前端只负责下载。
常见面试问题
Q1: 前端导出 Excel 有哪些方案?
答案:
| 方案 | 适用场景 | 优缺点 |
|---|---|---|
| SheetJS (xlsx) | 通用 | 功能全、社区版免费 |
| ExcelJS | 需要样式 | 支持样式、流式写入 |
| csv 拼接 | 简单表格 | 最简单、无样式 |
| 后端导出 | 大数据量 | 不占前端资源 |
Q2: 导出数据量大导致页面卡顿怎么办?
答案:
- Web Worker:将 Excel 生成移到 Worker 线程
- 分片处理:将数据分批写入
- Transferable Objects:Worker 返回 ArrayBuffer 时零拷贝传输
- 后端生成:超过阈值时走后端导出