React实现预览PDF
前段时间因为业务需求,要在web端进行PDF预览,后端返回的PDF是Blob格式,本来想着直接用react-pdf,但是按照官网demo操作报了一堆的错误,可能和webpack以及react的版本有关系,由于相关文档资料介绍的太少,最后还是决定使用pdfjs-dist。
首先说一下应用环境,以及相关插件安装的版本!
create-react-app@5.0.0 //脚手架版本
react@17.0.2 // react版本
pdfjs-dist@2.4.456 // pdfjs-dist版本
其他版本可能会出一些莫名奇妙的错误,可以查询相关文档进行解决,具体实现代码如下,相关包进入如下,具体可根据自己需要进行引入。
import React, { useState, useEffect, useCallback } from 'react';
import { Pagination, Button, Space, Spin } from 'antd';
import { PlusOutlined, MinusOutlined } from '@ant-design/icons';
import Axios from "axios";
import PDFJS from 'pdfjs-dist';
import workerSrc from 'pdfjs-dist/build/pdf.worker.entry'
PDFJS.workerSrc = workerSrc;
let pdfDoc;
下面是具体实现代码。
function PreviewPdf(){
const [loading, setLoading] = useState(false);//加载动画
const [pageNum, setPageNum] = useState(1);//当前页码
const [total, setTotal] = useState(0);//pdf总页数
const [scale, setScale] = useState(1.5);//pdf缩放比例
useEffect(() => {
setLoading(true);
Axios({
method: "get",
url: `url`,
params: {},
responseType: 'blob'
}).then((res) => {
const blob = new Blob([res.data], {
type: "application/pdf;chartset=UTF-8",
});
PDFJS.getDocument(URL.createObjectURL(blob)).promise.then((_pdfDoc) => {
setLoading(false);
pdfDoc = _pdfDoc;//pdfjs实例化对象
setTotal(_pdfDoc.numPages);//获得总数
renderPages(1, 1.5)//默认设置显示第一页,设置放大倍数为1.5倍
})
})
}, [renderPdf])
const renderPdf = useCallback((currentPageNum,currentScale)=>{
pdfDoc.getPage(currentPageNum).then((pageContent) => {
let canvas = document.getElementById("pdf-canvas");
let vp = pageContent.getViewport({ scale: s });
let ctx = canvas.getContext('2d')
let dpr = window.devicePixelRatio || 1
let bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;
let ratio = dpr / bsr;
let viewport = pageContent.getViewport({ scale: window.innerWidth / vp.width });
canvas.width = viewport.width * ratio
canvas.height = viewport.height * ratio
canvas.style.width = viewport.width + 'px'
ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
let renderContext = {
canvasContext: ctx,
viewport: viewport
}
pageContent.render(renderContext)
setPageNum(currentPageNum)
setScale(currentScale)
})
})
function handleScaleAdd() {//增大缩放倍数
renderPdf(pageNum, scale + 0.1);
}
function handleScaleSub() {//减小缩放倍数
if (scale > 0.5) {//小于0.5不再进行缩小
renderPages(pageNum, scale-0.1);
}
}
const pagination = {
total,
current: pageNum,
pageSize: 1,
size: "small",
showSizeChanger: false,
onChange: (current) => {
renderPdf(current, scale);
},
}
return (
<div className="pdf-wrap">
<Spin spinning={loading}>
<div className="pdf-container">
<canvas id="pdf-canvas"></canvas>
</div>
<div className="pdf-control">
<div className="pdf-control-page">
<Pagination {...pagination} />
</div>
<div className="pdf-control-zoom">
<Space>
<Button size="small" icon={<PlusOutlined />} onClick={handleScaleAdd} />
<Button size="small" icon={<MinusOutlined />} onClick={handleScaleSub} />
</Space>
</div>
</div>
</Spin>
</div>
)
}
样式如下
.pdf-wrap {
background-color: #fff;
display: flex;
flex-direction: column;
.pdf-container {
flex: 1;
overflow: auto;
text-align: center;
background-color: rgba(0, 0, 0, 0.2);
.water-mark {
display: none;
}
}
.pdf-control {
padding:12px;
height: 50px;
background: rgba(103, 103, 103, 1);
display: flex;
justify-content: space-between;
color: #fff;
}
}
\