乐于分享
好东西不私藏

Vue 项目导出 PDF 和 Excel,如何选效率翻倍

Vue 项目导出 PDF 和 Excel,如何选效率翻倍

在后台管理系统中,导出功能几乎是“标配能力”。

无论是报表导出 Excel、合同导出 PDF,还是页面截图归档,不同场景对应的实现方式都不一样。选型不当,后续很容易在清晰度、体积、性能或兼容性上踩坑。

这篇文章会把常见方案拆开讲清楚,并给出可直接复用的代码示例。

html2canvas + jsPDF

这是最容易落地的 PDF 导出方案:先把 DOM 渲染成图片,再写入 PDF。

  • • 优点:样式保留完整,所见即所得。
  • • 缺点:本质是图片,文本不可选中,文件体积通常偏大。

先安装依赖:

pnpm add html2canvas jspdf
// utils/exportPdf.tsimport html2canvas from "html2canvas";import jsPDF from "jspdf";export async function exportToPdf(  element: HTMLElement,  filename = "export.pdf",) {  // 截图  const canvas = await html2canvas(element, {    scale: 2, // 2倍分辨率,更清晰    useCORS: true, // 允许跨域图片    allowTaint: false,    backgroundColor: "#ffffff",  });  const imgData = canvas.toDataURL("image/png");  const imgWidth = 210; // A4 宽度(mm)  const imgHeight = (canvas.height * imgWidth) / canvas.width;  const pdf = new jsPDF({    orientation: imgHeight > 297 ? "portrait" : "portrait",    unit: "mm",    format: "a4",  });  // 如果内容超过一页,自动分页  let heightLeft = imgHeight;  let position = 0;  pdf.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight);  heightLeft -= 297;  while (heightLeft > 0) {    position = heightLeft - imgHeight;    pdf.addPage();    pdf.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight);    heightLeft -= 297;  }  pdf.save(filename);}

在 Vue 组件中这样调用:

<script setup>  import { ref } from "vue";  import { exportToPdf } from "@/utils/exportPdf";  const reportRef = ref(null);  const exporting = ref(false);  async function handleExport() {    exporting.value = true;    try {      await exportToPdf(reportRef.value, "月度报告.pdf");    } finally {      exporting.value = false;    }  }</script><template>  <div>    <button @click="handleExport" :disabled="exporting">      {{ exporting ? "导出中..." : "导出 PDF" }}    </button>    <!-- 要导出的内容 -->    <div ref="reportRef" class="report-content">      <h1>月度销售报告</h1>      <!-- ... 报告内容 ... -->    </div>  </div></template>

jsPDF

如果你需要可搜索、可复制、可选中的文本 PDF,更适合直接用 jsPDF 生成内容:

import jsPDF from "jspdf";// 注意:需要引入中文字体,否则中文会乱码// 可以从 jspdf-font 等库获取中文字体文件export function generateReport(data: ReportData) {  const doc = new jsPDF();  // 设置字体(需要先加载中文字体)  doc.setFont("NotoSansSC");  doc.setFontSize(20);  // 标题  doc.text("销售报告", 105, 20, { align: "center" });  // 正文  doc.setFontSize(12);  doc.text(`报告日期:${data.date}`, 20, 40);  doc.text(`总销售额:¥${data.totalSales.toLocaleString()}`, 20, 55);  // 表格(使用 jspdf-autotable 插件)  doc.autoTable({    head: [["产品", "数量", "金额"]],    body: data.items.map((item) => [item.name, item.qty, `¥${item.amount}`]),    startY: 70,  });  doc.save("销售报告.pdf");}

SheetJS 导出 Excel

SheetJS(xlsx)是前端最常用的 Excel 处理库之一,支持读取与写入多种表格格式。

先安装依赖:

pnpm add xlsx file-saverpnpm add -D @types/file-saver

基础导出

先从最常见的 JSON 数据导出开始:

// utils/exportExcel.tsimport * as XLSX from "xlsx";import { saveAs } from "file-saver";export function exportToExcel(  data: Record<string, any>[],  filename = "export.xlsx",  sheetName = "Sheet1",) {  // 创建工作表  const worksheet = XLSX.utils.json_to_sheet(data);  // 创建工作簿  const workbook = XLSX.utils.book_new();  XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);  // 生成文件并下载  const excelBuffer = XLSX.write(workbook, {    bookType: "xlsx",    type: "array",  });  const blob = new Blob([excelBuffer], {    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",  });  saveAs(blob, filename);}
<script setup>  import { exportToExcel } from "@/utils/exportExcel";  const tableData = ref([    { 姓名: "张三", 部门: "技术部", 薪资: 15000 },    { 姓名: "李四", 部门: "产品部", 薪资: 18000 },  ]);  function handleExport() {    exportToExcel(tableData.value, "员工数据.xlsx");  }</script>

多 Sheet 导出

如果需要一次性导出多份业务数据,可以写入多个 Sheet:

export function exportMultiSheet(  sheets: Array<{    name: string;    data: Record<string, any>[];  }>,  filename = "export.xlsx",) {  const workbook = XLSX.utils.book_new();  sheets.forEach(({ name, data }) => {    const worksheet = XLSX.utils.json_to_sheet(data);    XLSX.utils.book_append_sheet(workbook, worksheet, name);  });  const buffer = XLSX.write(workbook, { bookType: "xlsx", type: "array" });  const blob = new Blob([buffer], { type: "application/octet-stream" });  saveAs(blob, filename);}// 使用exportMultiSheet(  [    { name: "销售数据", data: salesData },    { name: "用户数据", data: userData },    { name: "产品数据", data: productData },  ],  "综合报表.xlsx",);

设置列宽和样式

除了数据本身,你还可以调整列宽、行高等基础展示样式:

export function exportWithStyle(data: any[], filename: string) {  const worksheet = XLSX.utils.json_to_sheet(data);  // 设置列宽  worksheet["!cols"] = [    { wch: 15 }, // 第一列宽度 15    { wch: 20 }, // 第二列宽度 20    { wch: 12 }, // 第三列宽度 12  ];  // 设置行高  worksheet["!rows"] = [    { hpt: 30 }, // 第一行(表头)高度 30  ];  const workbook = XLSX.utils.book_new();  XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");  const buffer = XLSX.write(workbook, { bookType: "xlsx", type: "array" });  saveAs(new Blob([buffer]), filename);}

从 HTML 表格直接导出

已有表格页面时,也可以直接从 DOM 表格生成 Excel:

export function exportFromTable(tableId: string, filename: string) {  const table = document.getElementById(tableId);  if (!table) return;  // 直接从 DOM 表格生成 Excel  const workbook = XLSX.utils.table_to_book(table);  const buffer = XLSX.write(workbook, { bookType: "xlsx", type: "array" });  saveAs(new Blob([buffer]), filename);}

方案对比

场景
推荐方案
说明
导出报表截图
html2canvas + jsPDF
样式完全保留,简单
导出可编辑 PDF
jsPDF 直接生成
需要处理中文字体
导出 Excel 数据
SheetJS
功能最强,格式支持最全
从表格直接导出
SheetJS table_to_book
最简单,一行代码

写在最后

导出功能看似简单,真正落地时通常会遇到不少细节问题:

  • • PDF 导出要重点关注中文字体与分页;html2canvas 方案可以绕过部分字体问题
  • • Excel 导出优先用 SheetJS,生态成熟、能力全面
  • • 大数据量导出要关注主线程卡顿,建议结合 Web Worker 做异步处理

文档:

  • • SheetJS 文档: https://docs.sheetjs.com
  • • jsPDF: https://github.com/parallax/jsPDF
  • • html2canvas: https://html2canvas.hertzen.com

#PDF导出 #Excel导出 #SheetJS #jsPDF #html2canvas #Vue3 #报表导出 #文件下载