前言
公司最近项目有个需求, 基于umi的h5项目, 就是在h5页面中需要展示用户使用模版生成的pdf, 想了几种技术方案
- iframe 最简单的方法, 但是外观不能自定义, 很丑
- pdf.js 最强大的pdf处理库, 但是基于原生js的方法使用起来很麻烦
- react-pdf 基于pdf.js进行封装, 既能使用pdf.js众多的功能, 也能快速适配框架的编写方式
所以最后一种方式就是最佳的, 虽然是现成而且成熟的库, 但是第一次使用难免会踩一些坑, 希望本文能帮助到新手
加载worker.js
虽然加载方式很多, 前端只需要记住这种方式, 另外就是不同版本的react-pdf依赖的worker版本也不同, 只要从目录pdfjs-dist/build/pdf.worker.min.js拷贝到你的服务器上, 这个js主要是为了处理二进制字符流生成canvas或svg, 需要大量计算,所以需要新增webWorker去处理
pdfjs.GlobalWorkerOptions.workerSrc = `https:your.domian.com/pdf.worker.min.js`;
source源
在react-pdf中
<Document file="somefile.pdf" onLoadSuccess={onDocumentLoadSuccess}>
<Page pageNumber={pageNumber} />
</Document>
官网示例只是写了个somefile.pdf, 但不是说后缀是个pdf就可以加载, 绝对路径相对路径都不行, 本地加载可以支持import方式
import PDF from '../../somefile.pdf';
function Index() {
return <Document file={PDF} onLoadSuccess={onDocumentLoadSuccess}>
<Page pageNumber={pageNumber} />
</Document>
}
http的方式要注意跨域, 假如服务器强制验证header的话, file可以这么设置
function Index() {
return <Document file={{ url: 'http://example.com/sample.pdf', httpHeaders: { 'X-CustomHeader': 'xxxxxxxxxxxx' }, withCredentials: true }} onLoadSuccess={onDocumentLoadSuccess}>
<Page pageNumber={pageNumber} />
</Document>
}
一次显示多页
react-pdf的示例是一页一页然后进行动态修改pageNumber来进行翻页, 那不想分页想一次性全部展示怎么做, 其实也简单, 只需要在Document中展示和页面数量一致的Page标签就可以, 也可以自定义展示页数, 多页的pdf展示与否取决于标签和标签中pageNumber的数值
const [totalPages, setTotalPages] = useState([])
function onDocumentLoadSuccess({ numPages = 1 }) {
const arr = new Array(numPages).fill(1)
setTotalPages(arr)
}
<Document
className={styles.pdf_container}
file={pdfUrl}
onLoadSuccess={onDocumentLoadSuccess}
>
{totalPages.map((item, i) => (
<Page
key={i}
className={styles.page_style}
pageNumber={i + 1}
scale={scale}
/>
))}
</Document>
屏蔽多余的样式
react-pdf默认样式中, 会把pdf上的字排列在page标签的下方, 其实没有必要, 大多数场景下,我们只想保留pdf上的部分, 这时候只需要保留canvas标签即可
<Page
key={i}
className={styles.page_style}
pageNumber={i + 1}
scale={scale}
/>
.page_style {
:not(canvas) {
display: none;
}
}
结尾
因为这次是在移动端, 我还会运用移动端的手势库对pdf进行拖拽和缩小放大操作