React PDF 预览

2024-07-09  本文已影响0人  清霆

使用 react-pdf,其中 pdfjs 需要设置 pdfjs.GlobalWorkerOptions.workerSrc,鉴于一些众所周知的原因,所以直接去 node_modulespdf.worker.min.mjs 放到public目录,锁死包版本,不要折腾别的了。
nginx 服务器需要修改对mjs的支持

# `nginx` 路径根据需要调整
vim /etc/nginx/mime.types
# 在下面这一行的 `js` 后面加上 `mjs`
application/javascript                 js;
# 如
application/javascript                 js mjs;
# 保存并退出
:wq
# 重启nginx
nginx -s reload
import { CSSProperties, useRef, useState } from 'react';
import { Document, Page, pdfjs } from 'react-pdf';
import { OnDocumentLoadSuccess } from 'react-pdf/dist/cjs/shared/types';
import { useSafeState } from 'ahooks';

// // pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.bootcdn.net/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.mjs`;
// pdfjs.GlobalWorkerOptions.workerSrc = new URL(
//   'pdfjs-dist/build/pdf.worker.min.mjs',
//   import.meta.url,
// ).toString();

pdfjs.GlobalWorkerOptions.workerSrc = '/js/pdf.worker.mjs';

interface Props {
  file?: string;
  onDocumentLoadSuccess?: OnDocumentLoadSuccess;
}

export default function Preview({
  file,
  onDocumentLoadSuccess: onLoad,
}: Props) {
  const [loaded, setLoaded] = useSafeState(false);
  const [numPages, setNumPages] = useState(1);
  const previewRef = useRef<HTMLDivElement>(null);
  const pdfRef = useRef<any>(null);

  const [boxStyle, setBoxStyle] = useSafeState<CSSProperties>({
    width: '100%',
    overflow: 'hidden',
  });
  const [pdfStyle, setPdfStyle] = useSafeState<CSSProperties>({
    width: 'fit-content',
    transform: 'scale(1)',
    transformOrigin: 'top left',
    overflow: 'hidden',
  });

  const onDocumentLoadSuccess: OnDocumentLoadSuccess = (e) => {
    const { numPages, ...rest } = e;
    setNumPages(numPages);
    onLoad?.(e);
  };
  const onPageLoadSuccess = (e: any, index: number) => {
    if (index === 0) {
      const previewWidth = previewRef.current!.clientWidth;
      const pdfWidth = e.width;
      const pdfHeight = e.height * numPages;
      if (previewWidth < pdfWidth) {
        const scale = (previewWidth / pdfWidth).toFixed(6);
        setPdfStyle({
          ...pdfStyle,
          transform: `scale(${scale})`,
        });
        setBoxStyle({
          height: `${pdfHeight * Number(scale) + 36}px`,
        });
        setLoaded(true);
      }
    }
  };
  return (
    <div ref={previewRef} style={boxStyle}>
      <div style={pdfStyle}>
        <Document
          ref={pdfRef}
          className={!loaded ? 'transparent' : null}
          file={file}
          onLoadSuccess={onDocumentLoadSuccess}
        >
          {new Array(numPages).fill(1).map((_, i: number) => {
            return (
              <Page
                key={i}
                className={'page'}
                pageNumber={i + 1}
                renderAnnotationLayer={false}
                renderTextLayer={false}
                onLoadSuccess={(e) => onPageLoadSuccess(e, i)}
              >
                <div className={'pageNo'}>
                  {i + 1} / {numPages}
                </div>
              </Page>
            );
          })}
        </Document>
      </div>
    </div>
  );
}
.preview {
  .transparent {
    opacity: 0;
  }
  .page {
    width: fit-content;
    position: relative;
    .pageNo {
      position: absolute;
      right: 8px;
      bottom: 8px;
    }
  }
}
上一篇下一篇

猜你喜欢

热点阅读