react-pdf实现pdf预览

实现了pdf翻页,放大,缩小,全屏展示,右键打印。

实现代码:
js:

import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Spin, Tooltip, Input } from 'antd';
import { LeftOutlined, RightOutlined, PlusCircleOutlined, MinusCircleOutlined, FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
import styles from './index.less';
import { Document, Page, pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
import stateStorage from '@/storage/stateStorage';

export default function PdfView({ file }) {
    console.log(file)
    const [pageNumber, setPageNumber] = useState(1)
    const [pageNumberInput, setPageNumberInput] = useState(1)
    const [pageNumberFocus, setPageNumberFocus] = useState(false)
    const [numPages, setNumPages] = useState(1)
    const [pageWidth, setPageWidth] = useState(600)
    const [fullscreen, setFullscreen] = useState(false)
    const onDocumentLoadSuccess = ({ numPages }) => {
        setNumPages(numPages)
    }

    const lastPage = () => {
        if (pageNumber == 1) {
            return
        }
        const page = pageNumber - 1
        setPageNumber(page)
        setPageNumberInput(page)
    }
    const nextPage = () => {
        if (pageNumber == numPages) {
            return
        }
        const page = pageNumber + 1
        setPageNumber(page)
        setPageNumberInput(page)
    }
    const onPageNumberFocus = e => {
        setPageNumberFocus(true)
    };
    const onPageNumberBlur = e => {
        setPageNumberFocus(false)
        setPageNumberInput(pageNumber)
    };
    const onPageNumberChange = e => {
        let value = e.target.value
        value = value <= 0 ? 1 : value;
        value = value >= numPages ? numPages : value;
        setPageNumberInput(value)
    };
    const toPage = e => {
        setPageNumber(Number(e.target.value))
    };

    const pageZoomOut = () => {
        if (pageWidth <= 600) {
            return
        }
        const pageWidths = pageWidth * 0.8
        setPageWidth(pageWidths)
    }
    const pageZoomIn = () => {
        const pageWidths = pageWidth * 2.5
        setPageWidth(pageWidths)

    }

    const pageFullscreen = () => {
        if (fullscreen) {
            setFullscreen(false)
            setPageWidth(600)
        } else {
            setFullscreen(true)
            setPageWidth(window.screen.width - 40)
        }
    }

    const getPrintRender = () => {
        return new Array(numPages || []).fill(0).map((ele, i) => {
            return (
                <Page key={i + 1} pageNumber={i + 1} width={750} loading={<Spin size="large" />} />
            )
        })
    }

    return (
        <div className={styles.view}>
            <div className={`${styles.pageContainer} ${styles.noPrint}`}>
                <Document
                    file={stateStorage.get('pdf')}
                    onLoadSuccess={onDocumentLoadSuccess}
                    loading={<Spin size="large" />}
                >
                    <Page pageNumber={pageNumber} width={pageWidth} loading={<Spin size="large" />} />
                </Document>
            </div>

            <div className={styles.canPrint}>
                <Document
                    file={stateStorage.get('pdf')}
                    onLoadSuccess={onDocumentLoadSuccess}
                    loading={<Spin size="large" />}
                >
                    {getPrintRender()}
                </Document>
            </div>

            <div className={`${styles.pageTool} ${styles.noPrint}`}>
                <Tooltip title={pageNumber == 1 ? '已是第一页' : '上一页'}>
                    <LeftOutlined onClick={lastPage} />
                </Tooltip>
                <Input value={pageNumberFocus ? pageNumberInput : pageNumber}
                    onFocus={onPageNumberFocus}
                    onBlur={onPageNumberBlur}
                    onChange={onPageNumberChange}
                    onPressEnter={toPage} type="number" /> / {numPages}
                <Tooltip title={pageNumber == numPages ? '已是最后一页' : '下一页'}>
                    <RightOutlined onClick={nextPage} />
                </Tooltip>
                <Tooltip title="放大">
                    <PlusCircleOutlined onClick={pageZoomIn} />
                </Tooltip>
                <Tooltip title="缩小">
                    <MinusCircleOutlined onClick={pageZoomOut} />
                </Tooltip>
                <Tooltip title={fullscreen ? '恢复默认' : '适合窗口'}>
                    {fullscreen ? <FullscreenExitOutlined onClick={pageFullscreen} /> : <FullscreenOutlined onClick={pageFullscreen} />}
                </Tooltip>
            </div>
        </div>
    )
}
PdfView.propTypes = {
    params: PropTypes.object.isRequired,
    file: PropTypes.any
};

css:

.view {
  background: #444;
  display: flex;
  justify-content: center;
  min-height: 100vh;
  padding: 50px 0;
  box-sizing: border-box;
}

.pageContainer {
  box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 4px 0px;
  width: max-content;
  max-width: 100vw;
}

.pageTool {
  position: fixed;
  bottom: 20px;
  background: rgb(66, 66, 66);
  color: white;
  padding: 8px 15px;
  border-radius: 15px;

  i {
    padding: 5px;
    margin: 0 5px;

    &:hover {
      background: #333;
    }
  }

  input {
    display: inline-block;
    width: 50px;
    text-align: center;
    margin-right: 10px;
    height: 24px;
  }

  input::-webkit-outer-spin-button,
  input::-webkit-inner-spin-button {
    -webkit-appearance: none;
  }

  input[type="number"] {
    -moz-appearance: textfield;
  }
}

.view {
  .canPrint {
    display: none;
  }

  @media print {
    .canPrint {
      display: block;
    }

    & {
      padding: 0;
    }

    &::-webkit-scrollbar {
      display: none;
    }

    .noPrint {
      display: none;
      height: 0;
    }

    :global {

      // react-pdf__Page__textContent隐藏 为了解决打印时会出现多一张空白页的情况
      .react-pdf__Page__textContent {
        display: none;
      }

      .react-pdf__Page:not(:last-child) {
        page-break-after: always;
      }
    }
  }
}

附:
react-pdf

THE END
posted @   ZerlinM  阅读(1724)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示