前端实现预览PDF
下载包 npm install react-pdf
我使用的是react-pdf@5.7.2版本
以下例子使用的是react创建的项目
直接上代码=>cv可用,保证高效
1.新增依赖
yarn add react-pdf@5.7.2
npm install react-pdf@5.7.2
2.导出js
/*
1.进入该组件时,通过路由传递path进来,形如:
history.push({ pathname: '/pdfPreview', query: { path } })
2.进入该组件时,通过props传递path进来,形如:
{ filePath :{ path :''} }
*/
import React, { useState } from 'react';
import { Spin, Tooltip, Input } from 'antd';
import {
LeftOutlined,
RightOutlined,
PlusCircleOutlined,
MinusCircleOutlined,
FullscreenOutlined,
FullscreenExitOutlined,
} 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`;
const pdfjsWorker = require('pdfjs-dist/build/pdf.worker.entry'); // 引用本地的
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
const PreviewPDF = (props: any) => {
const { location, filePDF, filePath } = props; // 方法1: 作为组件传入的值, 取出path(pdf地址)
// const { path }: any = location.query; // 方法2: 作为路由跳转的传入的值, 取出path(pdf地址)
const path = filePath;
const [pageNumber, setPageNumber] = useState(1);
const [pageNumberInput, setPageNumberInput] = useState(1);
const [pageNumberFocus, setPageNumberFocus] = useState(false);
const [numPages, setNumPages] = useState(1);
const [pageWidth, setPageWidth] = useState(1200);
const [fullscreen, setFullscreen] = useState(false);
const onDocumentLoadSuccess = ({ numPages }: any) => {
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 = () => {
setPageNumberFocus(true);
};
const onPageNumberBlur = () => {
setPageNumberFocus(false);
setPageNumberInput(pageNumber);
};
const onPageNumberChange = (e: any) => {
let { value } = e.target;
value = value <= 0 ? 1 : value;
value = value >= numPages ? numPages : value;
setPageNumberInput(value);
};
const toPage = (e: any) => {
setPageNumber(Number(e.target.value));
};
const pageZoomOut = () => {
if (pageWidth <= 1200) return;
const width = pageWidth * 0.8;
setPageWidth(width);
};
const pageZoomIn = () => {
const width = pageWidth * 1.2;
setPageWidth(width);
};
const pageFullscreen = () => {
if (fullscreen) {
setFullscreen(false);
setPageWidth(1200);
} else {
setFullscreen(true);
setPageWidth(window.screen.width - 40);
}
};
return (
<div className={`${styles.view}`}>
<div className={styles.pageContainer}>
<Document
file={path}
onLoadSuccess={onDocumentLoadSuccess}
loading={<Spin size="large" />}
options={{
// cMapUrl: `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/cmaps/`, // 解决打印不显示的问题,必要的
cMapUrl:'./cmaps/', // public路径 下载到本地
cMapPacked: true,
optimizedImages: true,
// disableWorker: true
}}
>
<Page pageNumber={pageNumber} width={pageWidth} loading={<Spin size="large" />} />
</Document>
</div>
<div className={styles.pageTool}>
<Tooltip title={pageNumber == 1 ? '已是第一页' : '上一页'}>
<LeftOutlined className={styles.outlined} onClick={lastPage} />
</Tooltip>
<Input
value={pageNumberFocus ? pageNumberInput : pageNumber}
onFocus={onPageNumberFocus}
onBlur={onPageNumberBlur}
onChange={onPageNumberChange}
onPressEnter={toPage}
type="number"
/>
/ {numPages}
<Tooltip title={pageNumber == numPages ? '已是最后一页' : '下一页'}>
<RightOutlined className={styles.outlined} onClick={nextPage} />
</Tooltip>
<Tooltip title="放大">
<PlusCircleOutlined className={styles.outlined} onClick={pageZoomIn} />
</Tooltip>
<Tooltip title="缩小">
<MinusCircleOutlined className={styles.outlined} onClick={pageZoomOut} />
</Tooltip>
<Tooltip title={fullscreen ? '恢复默认' : '适合窗口'}>
{fullscreen ? (
<FullscreenExitOutlined className={styles.outlined} onClick={pageFullscreen} />
) : (
<FullscreenOutlined className={styles.outlined} onClick={pageFullscreen} />
)}
</Tooltip>
</div>
</div>
);
};
export default PreviewPDF;
3.cv Css
.view {
display: flex;
justify-content: center;
height: 100%;
// height: 100vh;
padding: 20px 0;
// background: #444;
.pageContainer {
width: max-content;
max-width: 100%;
// overflow-y: scroll;
box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 4px 0px;
}
.pageTool {
position: absolute;
bottom: 60px;
left: -20px;
padding: 8px 15px;
color: white;
background: rgb(66, 66, 66);
// background-color: #fff;
border-radius: 15px;
.outlined {
margin: 0 10px;
user-select: none;
}
input {
display: inline-block;
width: 50px;
height: 24px;
margin-right: 10px;
text-align: center;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
input[type='number'] {
-moz-appearance: textfield;
}
}
}
4.引用组件
import PreviewPDF from './PreviewPDF';
/**
*
* @param file 数据返回的值,就是预览的pdf的path值
* 此处写的一个方法调用,获取path值,进行操作
*/
const handlePreview = async(file: any) => {
await setFilePath(file.url);
setVisiblePDF(true); // 组件方式预览
// const prefix = `${window.location.protocol}//${window.location.host}`;
// window.open(`${prefix}/#/binjiang-publicpower/previewPDF?path=${file.url}`); // 路由的方式预览, 新窗口打开
};
<Modal width={1400} destroyOnClose footer={false} visible={visiblePDF} onCancel={() => setVisiblePDF(false)} title={''}>
<PreviewPDF filePath={filePath} />
</Modal>
其实可以后端返回的链接添加参数(因为有些后端返回的是下载的链接),用自带的浏览器打开
默认的响应头是attachment,这里要改成inline,变成下载的
<a href={`${file.fileUrl || fileUrl}?dispositionType=inline`} target="_target"></a>