在 React 项目中预览 PDF 文件并实现下载功能

4,277 阅读1分钟

需求:在后端接口返回一个 PDF 文件地址的时候,需要在前端展示并分页

在网上找到了 react-pdf 这个 npm 包,下载之后根据示例写好
运行起来却报错:Failed to load PDF file.

image.png

原来是必须加上:

pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.js`;

问题:发现当 url 为空的时候会触发 error
报错:Invalid parameter object: need either .data, .range or .url

image.png

解决:查了原来不能这样写 file={{ url }}, 不能判断空值

分页功能

分页直接采用 antd 的分页器Pagination就可以

完整代码
<>
  // setTotal获取PDF的总页数
  <Document file={url} onLoadSuccess={({ numPages }) => setTotal(numPages)}>
    <Page key={page} pageNumber={page} width={600} />
  </Document>
  <Pagination
    style={{ marginTop: 20 }}
    total={total}
    showTotal={total => `共 ${total} 页`}
    current={page}
    pageSize={1}
    size="small"
    onChange={page => setPage(page)}
  />
</>

下载功能

下载最基本的实现就是在<a>标签中添加 download 属性就能实现下载.
但是遇到比如图片/PDF 等文件的时候,会变成打开新链接模式进行预览。
如果要实现下载功能,必须先将 url 中的文件转换成 blob 地址进行下载。

export const downloadFile = async (url: string, name: string) => {
  const { data } = await axios({
    method: 'get',
    baseURL: BACKEND_URL,
    url,
    headers: {
      accessToken: user.getToken(),
    },
  });
  const link = document.createElement('a');
  // 方法一
  fetch(data.data)
    .then(res => res.blob())
    .then(blob => {
      // 将链接地址字符内容转变成blob地址
      link.href = URL.createObjectURL(blob);
      link.download = `${name}.pdf`;
      document.body.appendChild(link);
      link.click();
      link.remove();
    });
  // 方法二
    link.href = URL.createObjectURL(res.data);
    link.download = `${name}.pdf`;
    document.body.appendChild(link);
    link.click();
    URL.revokeObjectURL(downloadUrl);
};

主要参考来源

  1. react-pdf