前端导出pdf,所见即所得

一、推荐方案:html2canvas + jsPDF(图片式PDF)

javascript

javascript 复制代码
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';

const exportPDF = async (elementId, fileName) => {
  const element = document.getElementById(elementId);
  
  // 1. 将DOM转为Canvas
  const canvas = await html2canvas(element, {
    scale: 2, // 提升清晰度
    useCORS: true, // 允许跨域图片
    logging: true, // 调试时开启
  });

  // 2. Canvas转图片数据
  const imgData = canvas.toDataURL('image/png', 1.0);
  
  // 3. 计算PDF尺寸
  const pdf = new jsPDF('p', 'mm', 'a4');
  const pageWidth = pdf.internal.pageSize.getWidth();
  const pageHeight = pdf.internal.pageSize.getHeight();
  const imgRatio = canvas.width / canvas.height;
  
  // 4. 自动适应页面大小
  let imgHeight = pageHeight;
  let imgWidth = pageWidth;
  if (pageWidth / imgRatio < pageHeight) {
    imgWidth = pageWidth;
    imgHeight = imgWidth / imgRatio;
  } else {
    imgHeight = pageHeight;
    imgWidth = imgHeight * imgRatio;
  }

  // 5. 添加图片到PDF
  pdf.addImage(imgData, 'PNG', 0, 0, imgWidth, imgHeight);
  
  // 6. 保存文件
  pdf.save(`${fileName}.pdf`);
};

// 使用示例
exportPDF('export-container', 'report');
复制代码

二、进阶方案:jsPDF内置HTML渲染(矢量文本)

javascript

javascript 复制代码
import { jsPDF } from "jspdf";

const exportPDF = async () => {
  const doc = new jsPDF('p', 'pt', 'a4');
  
  // 1. 获取需要导出的HTML元素
  const element = document.getElementById('content');
  
  // 2. 直接渲染HTML到PDF(需要配合html2canvas)
  await doc.html(element, {
    callback: (doc) => doc.save('document.pdf'),
    margin: [20, 20, 20, 20],
    autoPaging: 'text',
    width: 170, // 有效内容区宽度(mm)
    windowWidth: element.scrollWidth,
    html2canvas: {
      scale: 0.5, // 控制分辨率
      letterRendering: true,
    },
    x: 10,
    y: 10,
  });
};

三、专业方案:Puppeteer(需后端配合)

javascript

javascript 复制代码
// 前端
fetch('/generate-pdf', {
  method: 'POST',
  body: JSON.stringify({ html: document.documentElement.outerHTML }),
  headers: { 'Content-Type': 'application/json' }
});

// Node.js后端
const puppeteer = require('puppeteer');

app.post('/generate-pdf', async (req, res) => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.setContent(req.body.html);
  const pdf = await page.pdf({ 
    format: 'A4',
    printBackground: true 
  });
  await browser.close();
  res.setHeader('Content-Type', 'application/pdf');
  res.send(pdf);
});

四、样式优化要点

  1. 打印样式表

css

javascript 复制代码
@media print {
  @page { margin: 0; }
  body { -webkit-print-color-adjust: exact; }
  .no-print { display: none; }
}
  1. 强制分页

css

javascript 复制代码
.page-break {
  page-break-after: always;
  break-after: page;
}
  1. 字体处理

css

javascript 复制代码
@font-face {
  font-family: 'PDFFont';
  src: url('fonts/Songti.ttf') format('truetype');
}

body {
  font-family: 'PDFFont', sans-serif;
}
复制代码

五、方案对比

方案 优点 缺点
html2canvas+jsPDF 纯前端实现,视觉保真度高 文字变图片,文件体积较大
jsPDF HTML渲染 支持矢量文字,自动分页 兼容性问题,复杂布局易出错
Puppeteer 完美还原,支持复杂CSS 需要后端支持,消耗服务器资源
window.print() 零依赖,简单快捷 样式控制能力弱,交互体验差

六、常见问题处理

  1. 内容截断

javascript

javascript 复制代码
// 手动计算分页位置
const elementHeight = element.offsetHeight;
const pageHeight = 1122; // A4像素高度(96dpi)
if (elementHeight > pageHeight) {
  // 插入分页符逻辑
}
  1. 图片跨域

html

javascript 复制代码
​
<img crossorigin="anonymous" src="https://example.com/image.jpg">

​

运行 HTML

  1. 提升清晰度

javascript

javascript 复制代码
html2canvas(element, {
  scale: 3, // 最高3倍
  dpi: 300,
  letterRendering: true
});
复制代码

根据具体需求选择方案:需要快速实现选择方案一,注重文字质量选方案二,企业级应用推荐方案三。

相关推荐
Setsuna_F_Seiei4 小时前
前端转型 Agent 开发 04 之 MCP 与 Skill(赋予 Agent 更广工作能力)
前端·agent
刘发财5 小时前
前端2秒生成500页矢量PDF,rust真的强到没朋友
前端·javascript·rust
郑州光合科技余经理6 小时前
国际版外卖系统:税率字段怎么和订单主流程解耦
android·java·开发语言·前端·后端·php·ai编程
梦想平凡6 小时前
百游棋牌源代码开发搭建教程(十):隔离部署、备份恢复与双端验收
java·前端·javascript·数据库·源代码管理
yume_sibai8 小时前
06-Rust Web 开发实战(Axum 框架 + 数据库 + JWT 认证 + 中间件 + 部署)
前端·数据库·rust
计算机魔术师9 小时前
特朗普上台打给黄仁勋:AI末日论是骗局,我们绝不让它发生
前端
troy1289 小时前
Python 基础语法(八):Web 后端开发、数据分析与可视化、网络爬虫、人工智能 / 大模型应用
前端·python·数据分析
计算机魔术师9 小时前
CEO说要慢下来,黑客说别做梦了——同一篇论文,两种命运
前端
kyriewen10 小时前
我花3天抓了一个幽灵bug,凶手藏在第4层
前端·javascript·程序员
IT_陈寒10 小时前
Java里用Stream.parallel()翻车实录,这性能还不如单线程
前端·人工智能·后端