跳到主要内容

前端导出 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: 导出数据量大导致页面卡顿怎么办?

答案

  1. Web Worker:将 Excel 生成移到 Worker 线程
  2. 分片处理:将数据分批写入
  3. Transferable Objects:Worker 返回 ArrayBuffer 时零拷贝传输
  4. 后端生成:超过阈值时走后端导出

相关链接