使用react-pdf小结

1,321 阅读2分钟

前言

 公司最近项目有个需求, 基于umi的h5项目, 就是在h5页面中需要展示用户使用模版生成的pdf, 想了几种技术方案
  1. iframe 最简单的方法, 但是外观不能自定义, 很丑
  2. pdf.js 最强大的pdf处理库, 但是基于原生js的方法使用起来很麻烦
  3. 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进行拖拽和缩小放大操作