React-PDF
在您的React应用中像显示图片一样轻松地显示PDF。
迷路了?
这个包是用来"显示"已有的PDF。如果您想用React"创建"PDF,您可能在找@react-pdf/renderer。
简要说明
- 通过执行
npm install react-pdf
或yarn add react-pdf
安装。 - 通过添加
import { Document } from 'react-pdf'
导入。 - 通过添加
<Document file="..." />
使用。file
可以是URL、base64内容、Uint8Array等。 - 在
<Document />
内放置<Page />
组件来渲染页面。
演示
在sample
目录中可以找到一个最小化的演示页面。
也可以查看在线演示!
在继续之前
React-PDF正在持续开发中。本文档是为React-PDF 9.x分支编写的。如果您想查看其他版本的React-PDF文档,请使用GitHub页面顶部的下拉菜单切换到适当的标签。以下是每个分支最新文档的快速链接:
入门
兼容性
浏览器支持
React-PDF支持所有现代浏览器。它已在Chrome、Edge、Safari、Firefox和Opera的最新版本中进行了测试。
React-PDF v9默认支持以下浏览器:
- Chrome ≥119
- Edge ≥119
- Safari ≥17.4
- Firefox ≥121
您可以通过提供额外的polyfills(例如Array.prototype.at
、Promise.allSettled
或Promise.withResolvers
)并配置您的打包工具以转译pdfjs-dist
或使用旧版PDF.js worker来扩展支持的浏览器列表。
如果您需要支持更旧的浏览器,您需要使用React-PDF v6或更早版本。
React
要使用最新版本的React-PDF,您的项目需要使用React 16.8或更高版本。
如果您使用的是较旧版本的React,请参考下表找到合适的React-PDF版本。
React版本 | 最新兼容的React-PDF版本 |
---|---|
≥16.8 | 最新版 |
≥16.3 | 5.x |
≥15.5 | 4.x |
Preact
React-PDF可以与Preact一起使用。
安装
通过执行npm install react-pdf
或yarn add react-pdf
将React-PDF添加到您的项目中。
Next.js
如果您使用Next.js且未启用Turbopack,请在您的next.config.js
中添加以下内容:
module.exports = {
+ webpack: (config) => {
+ config.resolve.alias.canvas = false;
+ return config;
+ },
}
如果您使用Next.js且启用了Turbopack,请添加empty-module.ts
文件:
export default {};
并在您的next.config.js
中添加以下内容:
module.exports = {
+ experimental: {
+ turbo: {
+ resolveAlias: {
+ canvas: './empty-module.ts',
+ },
+ },
+ },
};
配置PDF.js worker
为了使React-PDF正常工作,需要提供PDF.js worker。您有几个选择。
导入worker(推荐)
对于大多数情况,以下示例将起作用:
import { pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
[!注意] 在Next.js中:
- 使用App Router时,确保在文件顶部添加
'use client';
。- 使用Pages Router时,确保在导入使用此代码的组件时禁用SSR。
[!注意] pnpm需要一个包含
public-hoist-pattern[]=pdfjs-dist
的.npmrc
文件才能正常工作。
查看更多示例
Parcel 2
对于Parcel 2,您需要使用稍微不同的代码:
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
- 'pdfjs-dist/build/pdf.worker.min.mjs',
+ 'npm:pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
将worker复制到public目录
您需要自行确保pdfjs-dist/build
中的pdf.worker.mjs
文件被复制到项目的输出文件夹中。
例如,您可以使用自定义脚本:
import path from 'node:path';
import fs from 'node:fs';
const pdfjsDistPath = path.dirname(require.resolve('pdfjs-dist/package.json'));
const pdfWorkerPath = path.join(pdfjsDistPath, 'build', 'pdf.worker.mjs');
fs.cpSync(pdfWorkerPath, './dist/pdf.worker.mjs', { recursive: true });
使用外部CDN
import { pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
旧版PDF.js worker
如果您需要支持较旧的浏览器,可以使用旧版PDF.js worker。要这样做,请按照上述说明进行操作,但在PDF.js worker导入路径中将/build/
替换为legacy/build/
,例如:
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
- 'pdfjs-dist/build/pdf.worker.min.mjs',
+ 'pdfjs-dist/legacy/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
或:
-pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
+pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
使用
以下是基本用法的示例:
import { useState } from 'react';
import { Document, Page } from 'react-pdf';
function MyApp() {
const [numPages, setNumPages] = useState<number>();
const [pageNumber, setPageNumber] = useState<number>(1);
function onDocumentLoadSuccess({ numPages }: { numPages: number }): void {
setNumPages(numPages);
}
返回 (
<div>
<Document file="somefile.pdf" onLoadSuccess={onDocumentLoadSuccess}>
<Page pageNumber={pageNumber} />
</Document>
<p>
第 {pageNumber} 页,共 {numPages} 页
</p>
</div>
);
}
请查看本仓库中的 sample 目录以获取完整的工作示例。更多示例和更高级的用例,请查看 React-PDF Wiki 中的 Recipes。
支持注释
如果你想在 React-PDF 渲染的 PDF 中使用注释(例如链接),那么你需要包含必要的样式表以正确显示注释,如下所示:
import 'react-pdf/dist/Page/AnnotationLayer.css';
支持文本层
如果你想在 React-PDF 渲染的 PDF 中使用文本层,那么你需要包含必要的样式表以正确显示文本层,如下所示:
import 'react-pdf/dist/Page/TextLayer.css';
支持非拉丁字符
如果你想确保包含非拉丁字符的 PDF 能够完美渲染,或者你遇到了以下警告:
警告:必须指定 CMap "baseUrl" 参数,请确保提供了 "cMapUrl" 和 "cMapPacked" API 参数。
那么你还需要在你的构建中包含 cMaps,并告诉 React-PDF 它们的位置。
复制 cMaps
首先,你需要从 pdfjs-dist
(React-PDF 的依赖项 - 如果你已安装 React-PDF,它应该在你的 node_modules
中)复制 cMaps。cMaps 位于 pdfjs-dist/cmaps
。
Vite
通过执行 npm install vite-plugin-static-copy --save-dev
或 yarn add vite-plugin-static-copy --dev
添加 vite-plugin-static-copy
,并在你的 Vite 配置中添加以下内容:
+import path from 'node:path';
+import { createRequire } from 'node:module';
-import { defineConfig } from 'vite';
+import { defineConfig, normalizePath } from 'vite';
+import { viteStaticCopy } from 'vite-plugin-static-copy';
+const require = createRequire(import.meta.url);
+
+const pdfjsDistPath = path.dirname(require.resolve('pdfjs-dist/package.json'));
+const cMapsDir = normalizePath(path.join(pdfjsDistPath, 'cmaps'));
export default defineConfig({
plugins: [
+ viteStaticCopy({
+ targets: [
+ {
+ src: cMapsDir,
+ dest: '',
+ },
+ ],
+ }),
]
});
Webpack
通过执行 npm install copy-webpack-plugin --save-dev
或 yarn add copy-webpack-plugin --dev
添加 copy-webpack-plugin
,并在你的 Webpack 配置中添加以下内容:
+import path from 'node:path';
+import CopyWebpackPlugin from 'copy-webpack-plugin';
+const pdfjsDistPath = path.dirname(require.resolve('pdfjs-dist/package.json'));
+const cMapsDir = path.join(pdfjsDistPath, 'cmaps');
module.exports = {
plugins: [
+ new CopyWebpackPlugin({
+ patterns: [
+ {
+ from: cMapsDir,
+ to: 'cmaps/'
+ },
+ ],
+ }),
],
};
其他工具
如果你使用其他打包工具,你需要自行确保 cMaps 被复制到你项目的输出文件夹中。
例如,你可以使用自定义脚本,如:
import path from 'node:path';
import fs from 'node:fs';
const pdfjsDistPath = path.dirname(require.resolve('pdfjs-dist/package.json'));
const cMapsDir = path.join(pdfjsDistPath, 'cmaps');
fs.cpSync(cMapsDir, 'dist/cmaps/', { recursive: true });
设置 React-PDF
现在你的构建中已经有了 cMaps,通过使用 options
属性向 Document 组件传递所需的选项,如下所示:
// 在 React 组件外部
const options = {
cMapUrl: '/cmaps/',
};
// 在 React 组件内部
<Document options={options} />;
[!注意] 确保在你的 React 组件外部定义
options
对象,如果不能,请使用useMemo
。
或者,你可以使用外部 CDN 的 cMaps:
// 在 React 组件外部
import { pdfjs } from 'react-pdf';
const options = {
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjs.version}/cmaps/`,
};
// 在 React 组件内部
<Document options={options} />;
支持标准字体
如果你想支持使用标准字体的 PDF(在 PDF 1.5 中已弃用,但仍在使用),或者你遇到了以下警告:
必须指定标准字体 "baseUrl" 参数,请确保提供了 "standardFontDataUrl" API 参数。
那么你还需要在你的构建中包含标准字体,并告诉 React-PDF 它们的位置。
复制字体
首先,你需要从 pdfjs-dist
(React-PDF 的依赖项 - 如果你已安装 React-PDF,它应该在你的 node_modules
中)复制标准字体。标准字体位于 pdfjs-dist/standard_fonts
。
Vite
通过执行 npm install vite-plugin-static-copy --save-dev
或 yarn add vite-plugin-static-copy --dev
添加 vite-plugin-static-copy
,并在你的 Vite 配置中添加以下内容:
+import path from 'node:path';
+import { createRequire } from 'node:module';
-import { defineConfig } from 'vite';
+import { defineConfig, normalizePath } from 'vite';
+import { viteStaticCopy } from 'vite-plugin-static-copy';
+const require = createRequire(import.meta.url);
+const standardFontsDir = normalizePath(
+ path.join(path.dirname(require.resolve('pdfjs-dist/package.json')), 'standard_fonts')
+);
export default defineConfig({
plugins: [
+ viteStaticCopy({
+ targets: [
+ {
+ src: standardFontsDir,
+ dest: '',
+ },
+ ],
+ }),
]
});
Webpack
通过执行 npm install copy-webpack-plugin --save-dev
或 yarn add copy-webpack-plugin --dev
添加 copy-webpack-plugin
,并在你的 Webpack 配置中添加以下内容:
+import path from 'node:path';
+import CopyWebpackPlugin from 'copy-webpack-plugin';
+const standardFontsDir = path.join(path.dirname(require.resolve('pdfjs-dist/package.json')), 'standard_fonts');
module.exports = {
plugins: [
+ new CopyWebpackPlugin({
+ patterns: [
+ {
+ from: standardFontsDir,
+ to: 'standard_fonts/'
+ },
+ ],
+ }),
],
};
其他工具
如果你使用其他打包工具,你需要自行确保标准字体被复制到你项目的输出文件夹中。
例如,你可以使用自定义脚本,如:
import path from 'node:path';
import fs from 'node:fs';
const pdfjsDistPath = path.dirname(require.resolve('pdfjs-dist/package.json'));
const standardFontsDir = path.join(pdfjsDistPath, 'standard_fonts');
fs.cpSync(standardFontsDir, 'dist/standard_fonts/', { recursive: true });
设置 React-PDF
现在你的构建中已经有了标准字体,通过使用 options
属性向 Document 组件传递所需的选项,如下所示:
// 在 React 组件外部
const options = {
standardFontDataUrl: '/standard_fonts/',
};
// 在 React 组件内部
<Document options={options} />;
[!注意] 确保在你的 React 组件外部定义
options
对象,如果不能,请使用useMemo
。
或者,你可以使用外部 CDN 的标准字体:
// 在 React 组件外部
import { pdfjs } from 'react-pdf';
const options = {
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjs.version}/standard_fonts`,
};
// React 组件内部
<Document options={options} />;
用户指南
Document
加载通过 file
属性传递的文档。
属性
属性名 | 描述 | 默认值 | 示例值 |
---|---|---|---|
className | 将添加到渲染元素的类名,与默认的 react-pdf__Document 一起使用。 | 不适用 |
|
error | 组件在发生错误时应显示的内容。 | "Failed to load PDF file." |
|
externalLinkRel | 注释中渲染的链接的 rel 属性。 | "noopener noreferrer nofollow" | rel 属性的有效值之一:
|
externalLinkTarget | 注释中渲染的外部链接的 target 属性。 | 未设置,将使用默认行为 | target 属性的有效值之一:
|
file | 要显示的 PDF。 可以是 URL、文件(通过 import … from … 导入或从表单元素的文件输入中获取),或带参数的对象(url - URL;data - 数据,最好是 Uint8Array;range - PDFDataRangeTransport)。警告:由于使用全等检查( === )来确定 file 对象是否已更改,必须通过将其设置在组件的状态、使用 useMemo 或其他类似技术来进行记忆化。 | 不适用 |
|
imageResourcesPath | 用于为注释 SVG 的 src 属性添加前缀的路径。 | 不适用(pdf.js 将回退到空字符串) | "/public/images/" |
inputRef | 类似于 ref 的属性,但它会传递给 <Document> 组件渲染的主 <div> 。 | 不适用 |
|
loading | 组件在加载时应显示的内容。 | "Loading PDF…" |
|
noData | 组件在没有数据时应显示的内容。 | "No PDF file specified." |
|
onItemClick | 点击大纲项目或缩略图时调用的函数。通常,你会使用这个回调来将用户移动到他们请求的位置。 | 不适用 | ({ dest, pageIndex, pageNumber }) => alert('Clicked an item from page ' + pageNumber + '!') |
onLoadError | 加载文档时发生错误时调用的函数。 | 不适用 | (error) => alert('Error while loading document! ' + error.message) |
onLoadProgress | 加载过程中可能多次调用的函数。 | 不适用 | ({ loaded, total }) => alert('Loading a document: ' + (loaded / total) * 100 + '%') |
onLoadSuccess | 文档成功加载时调用的函数。 | 不适用 | (pdf) => alert('Loaded a file with ' + pdf.numPages + ' pages!') |
onPassword | 加载受密码保护的 PDF 时调用的函数。 | 提示用户输入密码的函数。 | (callback) => callback('s3cr3t_p4ssw0rd') |
onSourceError | 从 file 属性检索文档源时发生错误时调用的函数。 | 不适用 | (error) => alert('Error while retrieving document source! ' + error.message) |
onSourceSuccess | 从 file 属性成功检索文档源时调用的函数。 | 不适用 | () => alert('Document source retrieved!') |
options | 一个对象,可以在其中定义要传递给 PDF.js 的其他参数。最值得注意的有:
注意:确保在 React 组件外部定义 options 对象,如果不行,请使用 useMemo 。 | 不适用 | { cMapUrl: '/cmaps/' } |
renderMode | 文档的渲染模式。可以是 "canvas" 、"custom" 或 "none" 。如果设置为 "custom" ,还必须提供 customRenderer 。 | "canvas" | "custom" |
rotate | 文档的旋转角度。如果提供,将全局更改旋转,即使对于已给定自己的 rotate 属性的页面也是如此。90 = 向右旋转,180 = 上下颠倒,270 = 向左旋转。 | 不适用 | 90 |
Page
显示一个页面。应放置在 <Document />
内部。或者,也可以传递 pdf
属性,该属性可以从 <Document />
的 onLoadSuccess
回调函数中获取,但一些高级功能(如渲染注释和文档内页面之间的链接)可能无法正常工作。
属性
属性名 | 描述 | 默认值 | 示例值 |
---|---|---|---|
canvasBackground | 画布背景颜色。可使用任何有效的 canvas.fillStyle 。 | 无 | "transparent" |
canvasRef | 类似于 ref 的属性,但它传递给 <Canvas> 组件渲染的 <canvas> 。 | 无 |
|
className | 将添加到渲染元素的类名,与默认的 react-pdf__Page 一起使用。 | 无 |
|
customRenderer | 自定义页面渲染方式的函数。使用此属性时必须将 renderMode 设置为 "custom" 。 | 无 | MyCustomRenderer |
customTextRenderer | 自定义文本层渲染方式的函数。 | 无 | ({ str, itemIndex }) => str.replace(/ipsum/g, value => `<mark>${value}</mark>`) |
devicePixelRatio | 当前设备上物理像素与设备独立像素(DIPs)之间的比率。 | window.devicePixelRatio | 1 |
error | 发生错误时组件应显示的内容。 | "Failed to load the page." |
|
height | 页面高度。如果未定义 height 和 width ,页面将以 PDF 中定义的大小渲染。如果同时定义 width 和 height ,将忽略 height 。如果同时定义 height 和 scale ,高度将乘以给定的系数。 | 页面默认高度 | 300 |
imageResourcesPath | 用于为注释 SVG 的 src 属性添加前缀的路径。 | 无(pdf.js 将默认使用空字符串) | "/public/images/" |
inputRef | 类似于 ref 的属性,但它传递给 <Page> 组件渲染的主 <div> 。 | 无 |
|
loading | 加载时组件应显示的内容。 | "Loading page…" |
|
noData | 无数据时组件应显示的内容。 | "No page specified." |
|
onGetAnnotationsError | 加载注释时发生错误时调用的函数。 | 无 | (error) => alert('Error while loading annotations! ' + error.message) |
onGetAnnotationsSuccess | 注释成功加载时调用的函数。 | 无 | (annotations) => alert('Now displaying ' + annotations.length + ' annotations!') |
onGetStructTreeError | 加载结构树时发生错误时调用的函数。 | 无 | (error) => alert('Error while loading structure tree! ' + error.message) |
onGetStructTreeSuccess | 结构树成功加载时调用的函数。 | 无 | (structTree) => alert(JSON.stringify(structTree)) |
onGetTextError | 加载文本层项目时发生错误时调用的函数。 | 无 | (error) => alert('Error while loading text layer items! ' + error.message) |
onGetTextSuccess | 文本层项目成功加载时调用的函数。 | 无 | ({ items, styles }) => alert('Now displaying ' + items.length + ' text layer items!') |
onLoadError | 加载页面时发生错误时调用的函数。 | 无 | (error) => alert('Error while loading page! ' + error.message) |
onLoadSuccess | 页面成功加载时调用的函数。 | 无 | (page) => alert('Now displaying a page number ' + page.pageNumber + '!') |
onRenderAnnotationLayerError | 渲染注释层时发生错误时调用的函数。 | 无 | (error) => alert('Error while loading annotation layer! ' + error.message) |
onRenderAnnotationLayerSuccess | 注释成功渲染到屏幕上时调用的函数。 | 无 | () => alert('Rendered the annotation layer!') |
onRenderError | 渲染页面时发生错误时调用的函数。 | 无 | (error) => alert('Error while loading page! ' + error.message) |
onRenderSuccess | 页面成功渲染到屏幕上时调用的函数。 | 无 | () => alert('Rendered the page!') |
onRenderTextLayerError | 渲染文本层时发生错误时调用的函数。 | 无 | (error) => alert('Error while rendering text layer! ' + error.message) |
onRenderTextLayerSuccess | 文本层成功渲染到屏幕上时调用的函数。 | 无 | () => alert('Rendered the text layer!') |
pageIndex | 应显示 PDF 文件中的哪一页,按页面索引。如果提供了 pageNumber 属性,则忽略此属性。 | 0 | 1 |
pageNumber | 应显示 PDF 文件中的哪一页,按页码。如果提供了此属性,将忽略 pageIndex 属性。 | 1 | 2 |
从 <Document /> 的 onLoadSuccess 回调函数中获取的 pdf 对象。 | (自动从父级 <Document /> 获取) | pdf | |
renderAnnotationLayer | 是否应渲染注释(如链接)。 | true | false |
renderForms | 是否应渲染表单。renderAnnotationLayer 属性必须设置为 true 。 | false | true |
renderMode | 文档的渲染模式。可以是 "canvas" 、"custom" 或 "none" 。如果设置为 "custom" ,还必须提供 customRenderer 。 | "canvas" | "custom" |
renderTextLayer | 是否应该渲染文本层。 | true | false |
rotate | 页面旋转的角度。90 = 向右旋转,180 = 上下颠倒,270 = 向左旋转。 | 页面的默认设置,通常为 0 | 90 |
scale | 页面缩放比例。 | 1 | 0.5 |
width | 页面宽度。如果未定义 height 和 width ,页面将以 PDF 中定义的大小进行渲染。如果同时定义了 width 和 height ,height 将被忽略。如果同时定义了 width 和 scale ,宽度将乘以给定的因子。 | 页面的默认宽度 | 300 |
大纲
显示大纲(目录)。应放置在 <Document />
内部。或者,可以传递 pdf
属性,该属性可以从 <Document />
的 onLoadSuccess
回调函数中获得。
属性
属性名 | 描述 | 默认值 | 示例值 |
---|---|---|---|
className | 将添加到渲染元素的类名,与默认的 react-pdf__Outline 一起使用。 | 无 |
|
inputRef | 行为类似于 ref,但传递给 <Outline> 组件渲染的主 <div> 。 | 无 |
|
onItemClick | 点击大纲项时调用的函数。通常,你会使用此回调将用户移动到他们请求的位置。 | 无 | ({ dest, pageIndex, pageNumber }) => alert('Clicked an item from page ' + pageNumber + '!') |
onLoadError | 检索大纲时发生错误时调用的函数。 | 无 | (error) => alert('Error while retrieving the outline! ' + error.message) |
onLoadSuccess | 成功检索大纲时调用的函数。 | 无 | (outline) => alert('The outline has been successfully retrieved.') |
缩略图
显示页面的缩略图。不渲染注释层或文本层。不将自身注册为链接目标,因此用户点击内部链接(例如目录中的链接)时不会滚动到缩略图组件。点击时,尝试导航到被点击的页面(类似于大纲中的链接)。应放置在 <Document />
内部。或者,可以传递 pdf
属性,该属性可以从 <Document />
的 onLoadSuccess
回调函数中获得。
属性
属性与 <Page />
组件相同,但某些与注释层和文本层相关的属性不可用:
- customTextRenderer
- onGetAnnotationsError
- onGetAnnotationsSuccess
- onGetTextError
- onGetTextSuccess
- onRenderAnnotationLayerError
- onRenderAnnotationLayerSuccess
- onRenderTextLayerError
- onRenderTextLayerSuccess
- renderAnnotationLayer
- renderForms
- renderTextLayer
此外,还提供了额外的属性:
属性名 | 描述 | 默认值 | 示例值 |
---|---|---|---|
className | 将添加到渲染元素的类名,与默认的 react-pdf__Thumbnail 一起使用。 | 无 |
|
onItemClick | 点击缩略图时调用的函数。通常,你会使用此回调将用户移动到他们请求的位置。 | 无 | ({ dest, pageIndex, pageNumber }) => alert('Clicked an item from page ' + pageNumber + '!') |
有用链接
许可证
MIT 许可证。
作者
致谢
如果没有 Niklas Närhinen 创建的原始版本以及 Mozilla 开发的 pdf.js,这个项目是不可能实现的。感谢你们!
赞助商
感谢所有赞助商,您的图片将出现在我们的 GitHub README 上。
支持者
感谢所有支持者,您的图片将出现在我们的 GitHub README 上。
主要贡献者
感谢所有为这个项目做出贡献的人!