使用
react-pdf
,其中pdfjs
需要设置pdfjs.GlobalWorkerOptions.workerSrc
,鉴于一些众所周知的原因,所以直接去node_modules
把pdf.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;
}
}
}