🧩 前端导出 PDF 全攻略:react-pdf 实战与性能优化指南(附完整示例)
💬 前言:当产品经理再次说“导出个 PDF 吧~”
👩💼 产品经理:能不能支持一下导出 PDF?就一个按钮,很简单的~
👨💻 前端:???
👩💼 产品经理:就和 Excel 一样嘛,一键下载那种。
👨💻 前端(内心 OS):Excel?PDF?一键?你怕不是想让我写打印机驱动 😭
听起来轻松的需求,做起来却是前端噩梦系列:
- 一导出就样式错乱;
- 中文字体全成方块;
- 图表模糊得像 240p;
- 文件一大就卡到浏览器假死。
于是我们开始疯狂搜索:
“react 导出 pdf 怎么实现”
“html2canvas 导出模糊怎么办”
“jsPDF 中文乱码解决方案”
最后发现,真正优雅的方案,其实藏在一个名字里:
🎯 @react-pdf/renderer —— 一个让你用 React 写 PDF 的神器。
一、前端导出 PDF 的几种主流方案
| 工具 / 库 | 核心思路 | 优点 | 缺点 |
|---|---|---|---|
| html2canvas + jsPDF | 把 DOM 截图再拼成 PDF | 快速上手,兼容性强 | 模糊、样式丢失、性能差 |
| react-pdf (@react-pdf/renderer) | React 组件直接渲染为 PDF | 结构清晰,质量高,可控性强 | 学习曲线略高 |
| pdfmake / pdf-lib | 手动构建 PDF 元素 | 灵活强大,版式精准 | 开发成本高,不适合复杂布局 |
| Puppeteer 服务端导出 | Headless Chrome 渲染 HTML | 精度高,接近打印效果 | 依赖后端,部署复杂 |
👉 如果你是做 报表 / 图表 / 结算表 / 发票导出,
推荐直接上 react-pdf,它是真正适合前端的方案。
二、react-pdf 是什么?
📘 官方地址: react-pdf.org/
📦 NPM 包: www.npmjs.com/package/@re…
@react-pdf/renderer 是一个将 React 组件直接渲染为 PDF 文档 的库。
它的核心理念:
「用 React 写 PDF,组件化地构建文档结构。」
核心优势:
- 🔤 矢量级清晰排版,文本可选中、可复制。
- 🧩 与 React 语法一致,支持组件与状态。
- 🖨️ 支持 Node、浏览器、流式输出,灵活部署。
三、快速上手:Hello PDF 👋
安装依赖
npm install @react-pdf/renderer
创建一个简单示例
import { Page, Text, View, Document, StyleSheet, pdf } from '@react-pdf/renderer';
// 样式定义
const styles = StyleSheet.create({
page: { padding: 20 },
title: { fontSize: 20, fontWeight: 'bold', marginBottom: 10 },
text: { fontSize: 12, lineHeight: 1.6 },
});
// PDF 文档组件
const MyDocument = () => (
<Document>
<Page style={styles.page}>
<Text style={styles.title}>React PDF 导出示例</Text>
<Text style={styles.text}>
这是一个使用 @react-pdf/renderer 生成的 PDF 文档。
</Text>
</Page>
</Document>
);
// 导出 PDF 的函数
const generatePdf = async () => {
const blob = await pdf(<MyDocument />).toBlob();
const url = URL.createObjectURL(blob);
window.open(url);
};
点击按钮 → 即可直接预览 PDF!
没有截图模糊、没有排版乱。
四、复杂场景:图表、表格、报表导出
✅ 图表导出
react-pdf 不直接支持 <canvas> / <svg>,
所以常见做法是:
- 用 ECharts / Chart.js 生成 base64 图;
- 再用
<Image src={base64} />插入 PDF。
const base64 = chartInstance.getDataURL();
<Image src={base64} />
✅ 表格导出
用 Flex 布局就能构建结构化表格:
<View style={{ flexDirection: 'row', borderBottom: '1px solid #ccc' }}>
<Text style={{ flex: 1 }}>产品</Text>
<Text style={{ flex: 1 }}>数量</Text>
<Text style={{ flex: 1 }}>金额</Text>
</View>
大表格可以用 wrap 自动分页:
<Page wrap> ... </Page>
五、中文字体与排版(重点⚠️)
默认字体库不支持中文,需要手动注册字体:
import { Font } from '@react-pdf/renderer';
import fontSrc from './fonts/NotoSansSC-Regular.ttf';
Font.register({
family: 'Noto Sans SC',
src: fontSrc,
});
const styles = StyleSheet.create({
text: { fontFamily: 'Noto Sans SC', fontSize: 12 },
});
✅ 推荐字体:
- 思源黑体(Noto Sans SC)
- 微软雅黑(Microsoft YaHei)
这样就能完美显示中文!
六、性能优化技巧
- 分页渲染:
大文档拆成多页异步渲染,避免阻塞。 - 延迟生成图表:
仅在导出时调用图表getDataURL()。 - 缓存静态模板:
对固定报表结构用预定义组件模板。 - 使用 Web Worker 导出:
避免主线程卡顿,保持导出体验流畅。
七、react-pdf vs html2canvas 对比总结
| 特性 | react-pdf | html2canvas + jsPDF |
|---|---|---|
| 清晰度 | ✅ 矢量级 | ❌ 模糊截图 |
| 文本可复制 | ✅ 可选中 | ❌ 不可复制 |
| 中文支持 | ✅ 可注册字体 | ❌ 容易乱码 |
| 性能 | ✅ 分页渲染 | ⚠️ 受 DOM 影响大 |
| 适合复杂布局 | ✅ 是 | ❌ 否 |
| 推荐指数 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
八、结语
“PDF 导出不是一个功能,而是一场排版与性能的平衡艺术。”
react-pdf 让前端 PDF 导出不再依赖截图,而是真正的文档构建。
无论是图表报告、月结账单、发票,还是统计分析,都能优雅搞定。
如果你的项目里有「导出 PDF」需求,
试试 @react-pdf/renderer ——
一次上手,终身不想回到 html2canvas。