pdf预览组件react-pdf,pdfjs-dist

文章讲述了如何在React应用中使用react-pdf库预览PDF文件,并提到在移动端遇到文件过大导致性能问题,通过分页和代码优化来改善用户体验。作者还强调了正确设置pdfjs的workerSrc版本对于确保代码正常运行的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   "react": "^17.0.2" 

1.react去预览pdf文件,并且这个组件可以在移动端展示,但要注意安装版本

 "react-pdf": "^5.7.2"

直接上代码了,做了一个两页的分页,因为放在移动端有个问题,有个文件全部加载手机就卡死了,但这个分页也没解决问题,换了个文件就是好的,代码能优化的地方比较多,自行优化:

import React, { useState, useEffect, useCallback } from 'react';
import { Page, pdfjs } from "react-pdf";
import { Document } from 'react-pdf/dist/esm/entry.webpack';

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

const PdfViewer = ({ file }: any) => {
    const [page_jsx, set_page_jsx]: [any[], React.Dispatch<React.SetStateAction<any[]>>] = useState<any[]>([]);
    const [totalPages, setTotalPages]: [number, React.Dispatch<React.SetStateAction<number>>] = useState(0);
    const [end_num, set_end_num]: [any, React.Dispatch<React.SetStateAction<any>>] = useState(6);

    const viewMore = useCallback(() => {
            let current_end_num = end_num + 5 <= totalPages ? end_num + 5: totalPages;
            set_end_num(current_end_num);
            const array = [];
            for (let i = current_end_num - 6; i < current_end_num; i++) {
                array.push(i);
            }
            let pageJsx = array?.map((a: any) => <Page scale={.5} key={`page_${a}`} pageNumber={a + 1}/>);
            set_page_jsx((jsx_arr: any[]) => [...jsx_arr, ...pageJsx]);
    }, [end_num, totalPages, set_end_num, set_page_jsx])

    useEffect(() => {
      const array = [];
      if (end_num === 6) {
        for (let i = totalPages < 6 ? 0: end_num - 6; i < (totalPages < 6 ? totalPages: end_num); i++) {
            array.push(i);
        }
        let pageJsx = array?.map((a: any) => <Page scale={.5} key={`page_${a}`} pageNumber={a + 1}/>);
        set_page_jsx((jsx_arr: any[]) => [...jsx_arr, ...pageJsx]);
      }
    }, [end_num, set_page_jsx, totalPages])

  return (
    <div style={{ width: '100%', height: '100vh', overflow: 'auto' }}>
        <Document
            className={"pdf-content"}
            file={file}
            onLoadSuccess={({ numPages }: any) => setTotalPages(numPages)}
        >
            {page_jsx?.map((page: any) => page)}
            {totalPages > end_num && <div style={{height: '40px', lineHeight: '40px', textAlign: 'center'}} onClick={() => viewMore()}>View more</div>}
        </Document>
    </div>
  );
};

export default PdfViewer;

2.   pdfjs-dist

"pdfjs-dist": "^2.5.207",这个插件的版本尤其要记录下,网上查了好多,只把代码放上去,如果版本不对,引入文件路径是不存在的,那么还是直接放代码吧,如第一种方法自行优化下:

import React, { useCallback, useEffect, useRef, useState } from 'react';
const pdfjsLib = require('pdfjs-dist/es5/build/pdf.js');

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

const PdfViewer = ({ file }: any) => {
  const [totalPages, setTotalPages]: [number, React.Dispatch<React.SetStateAction<number>>] = useState(0);
  const [end_num, set_end_num]: [any, React.Dispatch<React.SetStateAction<any>>] = useState(6);
  const canvasRefs: any = useRef([]);
  const pageNums: any = useRef([]);

  const renderPage = useCallback(async (pdf: any, endNum: any) => {
    pageNums.current = new Array(endNum)?.fill(0).map((_, i) => i + 1);
    
    // 渲染每一页
    for (let i = totalPages < 6 ? 1: endNum - 5; i <= (totalPages < 6 ? totalPages: endNum); i++) {
      const page = await pdf.getPage(i);
      const viewport = page.getViewport({ scale: 1.5 });

      // 创建canvas元素
      const canvas = document.createElement('canvas');
      const context = canvas.getContext('2d');
      canvas.height = viewport.height;
      canvas.width = viewport.width;

      // 将canvas添加到DOM中
      const canvasContainer: any = document.getElementById('pdf-container');
      canvasContainer.appendChild(canvas);

      // 存储canvas的引用以便后续操作
      canvasRefs.current[i - 1] = canvas;

      // 渲染页面
      const renderContext = {
        canvasContext: context,
        viewport: viewport
      };
      await page.render(renderContext);
    }
  }, [totalPages])

  useEffect(() => {
    async function loadPdf() {
      const loadingTask = pdfjsLib.getDocument(file);
      const pdf: any = await loadingTask.promise;
      // 获取总页数
      const numPages: any = pdf.numPages;
      setTotalPages(numPages);
      renderPage(pdf, end_num);
    }

    if (file && end_num === 6) {
      loadPdf();
    }
  }, [file, end_num, renderPage])

  return (
    <>
      <div id="pdf-container">
        {/* 在这里,canvas元素将被动态添加到这个容器中 */}
      </div>
      {totalPages > end_num && <div onClick={async () => {
        if (end_num < totalPages) {
          let current_end_num = end_num + 5 <= totalPages ? end_num + 5: totalPages;
          set_end_num(current_end_num);
          const loadingTask = pdfjsLib.getDocument(file);
          const pdf: any = await loadingTask.promise;
          renderPage(pdf, current_end_num);
        }
      }} style={{height: '40px', lineHeight: '40px', textAlign: 'center'}}>View more</div>}
    </>
    
  );
};

export default PdfViewer;

### 集成 `pdfjs-dist` 库到 React 项目 为了在 React 项目中集成并使用 `pdfjs-dist` 来实现 PDF 文件预览,可以按照如下方法操作: #### 安装依赖包 首先,在命令行工具中执行 npm 或 yarn 命令来安装必要的软件包。 ```bash npm install pdfjs-dist --save ``` 或者如果偏好使用 Yarn,则运行: ```bash yarn add pdfjs-dist ``` 这会下载 `pdfjs-dist` 及其所需的全部依赖项至项目的 node_modules 目录下[^1]。 #### 加载 Web Worker 和 CMap 资源文件 由于 `pdfjs-dist` 默认配置需要加载 worker 和 cmap 字符映射表资源,因此还需要引入这些辅助脚本。可以在入口 JavaScript 文件 (通常是 index.js 或 main.jsx) 的顶部加入以下代码片段以确保它们被正确加载。 ```javascript import * as pdfjsLib from 'pdfjs-dist'; // 如果使用构建版本则需指定worker路径 pdfjsLib.GlobalWorkerOptions.workerSrc = new URL( 'pdfjs-dist/build/pdf.worker.min.js', import.meta.url, ).toString(); ``` 这段设置指定了用于处理 PDF 解析工作的 web worker 所处的位置,这对于提高性能至关重要[^2]. #### 创建自定义组件渲染 PDF 文档页面 创建一个新的 React 组件用来显示单页或多页的 PDF 内容。下面是一个简单的例子展示了如何读取远程服务器上的 PDF 并逐页呈现出来。 ```jsx import React, { useState, useEffect } from 'react'; import * as pdfjsLib from 'pdfjs-dist'; const PdfViewer = ({ url }) => { const [numPages, setNumPages] = useState(null); function onDocumentLoadSuccess({ numPages }) { setNumPages(numPages); } async function renderPage(pageNumber) { try { let loadingTask = pdfjsLib.getDocument(url); const pdf = await loadingTask.promise; const page = await pdf.getPage(pageNumber); var scale = 1.5; // 放大比例 var viewport = page.getViewport({ scale }); // 准备 canvas 元素绘制 PDF 页面图像 let canvas = document.createElement('canvas'); let context = canvas.getContext('2d'); canvas.height = viewport.height; canvas.width = viewport.width; // 将 canvas 添加到 DOM 结构里 document.body.appendChild(canvas); // 渲染 PDF 页面内容到 canvas 上下文中去 const renderContext = { canvasContext: context, viewport: viewport }; await page.render(renderContext).promise; } catch(error){ console.error(`Error rendering page ${pageNumber}:`, error.message); } } useEffect(() => { if (!url || !window.URL.createObjectURL) return; fetch(url) .then(response => response.blob()) .then(blobData => { const objectUrl = window.URL.createObjectURL(blobData); pdfjsLib.getDocument(objectUrl).promise.then(onDocumentLoadSuccess); }) .catch(err => console.log(err)); }, [url]); return ( <div> {Array.from(new Array(numPages), (_, i) => <button key={i} onClick={() => renderPage(i + 1)}> Page {i + 1} </button>)} </div> ); }; export default PdfViewer; ``` 此组件接收一个名为 `url` 的属性作为输入参数,该参数指向待查看的 PDF 文件位置;通过调用 `renderPage()` 方法可按需动态生成各页视图[^3].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值