闻心阁

一蓑烟雨看苍生,半壶浊酒笑红尘

React中实现PDF的在线预览功能

2022-06-05 约 1 分钟读完 搬砖秘籍

最近项目中遇到了PDF预览的需求,客户要求可以在线查看PDF文件内容,不想下载下来再打开,踩了一些坑,做一个总结。

最简单的实现方式

目前几乎市面上的浏览器都原生支持了PDF预览功能,也就是说把一个在线的pdf地址,直接放在浏览器里是可以直接打开的。所以实现思路很简单粗暴,直接内嵌一个iframe就可以实现预览。

基本所有的功能都齐全了,如果不是极致要求兼容和一致性,都使用这个方案。

PDF.js

这是mozilla开源的一个前端pdf渲染框架,目前市面上常见的PDF渲染库基本都是基于它做的封装。

我没有采用这种方案是因为它默认是单独启动一个html,然后把pdf地址传进去,我个人不太喜欢。

React-pdf

react-pdf是基于pdf.js的封装,可以使用React的语法去灵活自定义。

安装

npm install react-pdf

// or

yarn add react-pdf

配置

详细配置方案参考官网:wojtekmaj/react-pdf: Display PDFs in your React app as easily as if they were images.

说一下我的配置方法,我没有使用本地的配置,使用的是CDN,一方面项目本身已经比较大了,还有一方面是后面可能要对webpack升级,就先不折腾。

PS:如果你的部署环境完全是内网运行的,不要用我这种方法。

需要配置2个内容,一个是worker,一个是cmap(这个不配置好像也能用),如下:

// 配置worker
pdfjs.GlobalWorkerOptions.workerSrc = `//cdn.staticfile.org/pdf.js/${pdfjs.version}/pdf.worker.min.js`;

cmap的配置在Document组件里设置,我使用也还是CDN。

<Document options={{
  cMapUrl: `https://unpkg.com/browse/pdfjs-dist@${pdfjs.version}/cmaps/`,
  cMapPacked: true,
}} file={url} onLoadSuccess={onDocumentLoadSuccess}>
  {Array.from(
    new Array(numPages),
    (el, index) => (
      <Page
        renderTextLayer={false}
        width={740}
        key={`page_${index + 1}`}
        pageNumber={index + 1}
      />
    )
  )}
</Document>

上面的代码实现的是把所有的PDF页面渲染出来,效果如图:

遇到的问题

在渲染知网论文的时候会有一些中文无法显示的情况出现,搜索了一下似乎是bug,参考这里:Chinese type 1 font does not render: Warning: Unknown type 1 charstring command of “0” · Issue #5790 · mozilla/pdf.js,解决方案参考这里:Error during font loading: Unable to load binary CMap at: ../web/cmaps/GBK-EUC-H.bcmap · Issue #10660 · mozilla/pdf.js

参考

  1. mozilla/pdf.js: PDF Reader in JavaScript

  2. wojtekmaj/react-pdf: Display PDFs in your React app as easily as if they were images.