前端导出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
});
复制代码

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

相关推荐
GoodStudyAndDayDayUp16 分钟前
gitlab+portainer 实现Ruoyi Vue前端CI/CD
前端·vue.js·gitlab
程序员阿明22 分钟前
vite运行只能访问localhost解决办法
前端·vue
前端 贾公子24 分钟前
uniapp -- 验证码倒计时按钮组件
前端·vue.js·uni-app
淡笑沐白30 分钟前
AJAX技术全解析:从基础到最佳实践
前端·ajax
龙正哲1 小时前
如何在Firefox火狐浏览器里-安装梦精灵AI提示词管理工具
前端·firefox
徐徐同学1 小时前
轻量级Web画板Paint Board如何本地部署与随时随地在线绘画分享
前端
LuckyLay1 小时前
Vue百日学习计划Day4-8——Gemini版
前端·vue.js·学习
八戒社1 小时前
WooCommerce短代码Shortcodes使用方法
前端·wordpress·woocommerce
小二·2 小时前
ECharts:数据可视化的强大引擎
前端·信息可视化·echarts
蓝婷儿3 小时前
第二章:CSS秘典 · 色彩与布局的力量
前端·css