适合:已经会一点 React,想在前端用代码生成 PDF(简历、小票、报告、证书等),还不熟悉 @react-pdf/renderer 的读者。
一、它是什么?和「打印网页」有什么区别
@react-pdf/renderer:用 React 组件描述 PDF 的每一页、每一块文字和布局,在浏览器或 Node 里排版并输出 PDF 文件(常见是 Blob,再触发下载)。- 浏览器「打印 → 另存为 PDF」:那是把 HTML/CSS 交给打印引擎,版式受浏览器影响大,难做到像素级可控。
- React-PDF:版式主要由 Flex(类似 React Native 的子集)控制,不是完整 Chrome CSS。学会「用 View 搭盒子、用 Text 写字」就能上手。
二、安装
在项目根目录执行(npm / yarn / pnpm 任选其一):
npm install @react-pdf/renderer
版本以官方当前稳定版为准;大版本升级时以 changelog 为准做回归。
三、第一个 PDF:Document → Page → Text
新建一个组件(名字随意),结构永远是:
- 最外层:
<Document>------ 表示「整份 PDF」。 - 里面至少一个:
<Page>------ 表示「一页纸」,常用size="A4"。 - 页里写内容:
<Text>、<View>等。
javascript
import { Document, Page, Text, View, StyleSheet, PDFDownloadLink } from '@react-pdf/renderer';
const styles = StyleSheet.create({
page: {
padding: 40,
fontSize: 12,
},
title: {
fontSize: 20,
marginBottom: 12,
},
});
function MyFirstPdf() {
return (
<Document>
<Page size="A4" style={styles.page}>
<Text style={styles.title}>你好,PDF</Text>
<Text>这是第一段正文。</Text>
</Page>
</Document>
);
}
export function App() {
return (
<PDFDownloadLink document={<MyFirstPdf />} fileName="demo.pdf">
{({ loading }) => (loading ? '生成中...' : '下载 PDF')}
</PDFDownloadLink>
);
}
运行后点击链接,浏览器会下载 demo.pdf。
要点:
Document下必须有Page,否则不合法。StyleSheet.create({...})里写样式,单位上fontSize一般按「点 pt」理解(和 Word 里字号习惯接近)。
四、布局核心:把 View 当成 div + Flex
React-PDF 里没有 div,块级容器用 View。排版主要靠 Flex(默认列方向可改):
javascript
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 8,
},
box: {
width: '45%',
padding: 8,
borderWidth: 1,
borderColor: '#ccc',
},
});
// 在 <Page> 里:
<View style={styles.row}>
<View style={styles.box}>
<Text>左侧</Text>
</View>
<View style={styles.box}>
<Text>右侧</Text>
</View>
</View>
初学者记住三句话:
- 先
View分区,再在分区里放Text。 width/height能写数字就写数字;百分比在部分场景可用,复杂时优先明确尺寸。- 多页 = 多个
<Page>,或内容太高时由库分页(与模板结构有关)。
五、样式常用属性(够用版)
| 用途 | 属性示例 |
|---|---|
| 内边距 | padding: 24 |
| 外边距 | marginBottom: 12 |
| 字号 | fontSize: 11 |
| 字重 | fontWeight: 'bold' |
| 颜色 | color: '#333333' |
| 行高 | lineHeight: 1.5 |
| 背景 | backgroundColor: '#f5f5f5' |
| 边框 | borderWidth, borderColor |
和网页 CSS 不一致的地方:很多选择器、浮动、Grid 等没有或行为不同;以 Flex 为主最省心。
六、中文与自定义字体(必看)
内置字体对 中文、日文 支持往往不够,会出现方框或乱码。要用 Font.register 注册自己的字体文件(.ttf / .otf),再在 StyleSheet 里写 fontFamily(与注册时的 family 一致)。
javascript
import { Font, Document, Page, Text, StyleSheet } from '@react-pdf/renderer';
Font.register({
family: 'MyCN',
src: 'https://你的CDN或静态站/字体/NotoSansSC-Regular.ttf',
});
Font.register({
family: 'MyCN',
src: 'https://你的CDN或静态站/字体/NotoSansSC-Bold.ttf',
fontWeight: 'bold',
});
const styles = StyleSheet.create({
page: {
padding: 40,
fontFamily: 'MyCN',
fontSize: 11,
},
});
注意:
- Regular 和 Bold 一般要分别注册(
fontWeight不同)。 - 字体 URL 必须浏览器能访问;若字体在你自己服务器上,注意 CORS。
- 字体文件可能很大,生产环境常用 子集字体 减小体积(字体工具另学即可)。
七、不用「下载链接」:用 pdf() 自己拿 Blob
按钮点击后生成再下载,更适合和表单状态绑在一起:
javascript
import { pdf, Document, Page, Text } from '@react-pdf/renderer';
async function handleDownload() {
const blob = await pdf(
<Document>
<Page size="A4">
<Text>动态内容:{new Date().toLocaleString()}</Text>
</Page>
</Document>
).toBlob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'report.pdf';
a.click();
URL.revokeObjectURL(url);
}
pdf(...) 还支持 .toBuffer()(Node)等,见官方 API。
八、在页面里「预览」PDF(进阶一小步)
下载前先预览,常见两种思路:
PDFViewer(若当前版本仍提供):直接把<Document>嵌进去,适合快速原型。usePDFhook:生成 blob URL,再配合react-pdf(pdf.js)在<canvas>里画出来,自定义程度高。
用 react-pdf 时务必配置 worker,否则容易白屏或报错:
import { pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.mjs'; // 从 node_modules 拷贝到 public
具体路径以官方 react-pdf 文档为准。
九、初学者最常踩的坑
- 忘包
Document/Page→ 直接报错或空白。 - 中文没注册字体 → 方块字。
- 把网页 CSS 照搬进来 → 大量无效;改学 Flex + 官方支持的属性列表。
Text里嵌套复杂结构 → 尽量扁平:多段就用多个Text或多个View包一层。- 图片不显示 → 检查 URL、HTTPS、CORS;本地
file://常有限制。 - 升级大版本 → 先看 breaking changes,PDF 类项目建议锁小版本并做好样张回归。
十、建议你练手的顺序
- 单页 A4:
Text+Viewflex 排一版简单简历壳子。 - 接上
Font.register,把中文跑通。 - 用
pdf().toBlob()做下载按钮。 - 把「姓名、电话」等改成 props,体会数据驱动。
- 再学
Image、多Page、或官方示例里的表格模式。
官方示例仓库:https://github.com/diegomura/react-pdf/tree/master/packages/renderer/examples
小结
- 用
Document→Page→View/Text搭结构。 - 用
StyleSheet.create+ Flex 控制版式。 - 中文必须
Font.register。 - 下载用
PDFDownloadLink或pdf().toBlob()均可。
把以上几步跑通,你就具备了在真实项目里接「动态数据生成 PDF」的基础;之后再学分页、页眉页脚、复杂表格即可。