前言:
最近和小伙伴们一起合作完成一个企业级知识库项目,其中一个功能就是后端把所有格式的文件转换为PDF,前端实现渲染PDF文件从而实现预览,干了整整一周(考虑到低版本浏览器的兼容),试用了几种方案(iframe预览已被废弃,不适用本项目,想了解的同学自行搜索),终于实现了这个功能。
pdfjs-dist展示pdf文档的原理,实际上是将pdf中的内容渲染到解析,然后渲染到 canvas
中进行展示,因此我们使用pdfjs渲染出来的pdf文件,实际上是一张张canvas图片。
pdfjs-dist下载官网
建议安装: "pdfjs-dist": "^2.12.313"
npm i [email protected]
打开VScode,使用ctl+`打开控制台,输入:npm i pdfjs-dist 安装pdfjs-dist 切记要指定版本
话不多说,上代码:
import { onMounted, ref, reactive } from 'vue'
const props = defineProps({
pdfUrl: {
type: String,
default: '/testPdf.pdf',
required: true,
},
containerWidth: {
type: Number,
default: 700,
required: true,
},
});
const pdfParams = reactive({
currentPageNumber: 1,
pdfScale: 1.0,
pdfPageTotal: 0, // 总页数
});
// 不要定义为ref或reactive格式,就定义为普通的变量
let pdfDoc = null;
// 这里必须使用异步去引用pdf文件,直接去import会报错,也不知道为什么
const loadFile = async () => {
let pdfjs = await import('pdfjs-dist/build/pdf')
let pdfjsWorker = await import('pdfjs-dist/build/pdf.worker.entry')
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker
// 此文件位于public/testPdf.pdf
pdfjs.getDocument(props.pdfUrl).promise.then(async doc => {
pdfDoc = doc
pdfParams.pdfPageTotal = doc.numPages
// // 仅加载第一页 注释 取消页码切换
// await getPdfPage(pdfParams.currentPageNumber)
// 加载pdf所有页
for (let pageNum = 1; pageNum <= doc.numPages; pageNum++) {
await getPdfPage(pageNum)
}
})
}
// 加载pdf的某一页
const getPdfPage = (number) => {
return new Promise((resolve, reject) => {
pdfDoc.getPage(number).then(page => {
const canvas = document.getElementById(`pdf-render${number}`)
const context = canvas.getContext('2d')
const scale = 1; // 缩放比例
const dpr = window.devicePixelRatio || 1;
const bsr =
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio ||
1;
const ratio = dpr / bsr;
const viewport = page.getViewport({ scale: pdfParams.pdfScale }); // 获取窗口大小
const canvasWidth = Math.floor(viewport.width * ratio);
const canvasHeight = Math.floor(viewport.height * ratio);
// const canvasWidth = props.containerWidth;
// const canvasHeight = Math.floor(viewport.height * ratio) * (props.containerWidth / Math.floor(viewport.width * ratio));
canvas.width = canvasWidth;
canvas.height = canvasHeight;
// canvas.style.width = Math.floor(viewport.width) + 'px'
// canvas.style.height = Math.floor(viewport.height) + 'px'
canvas.style.width = Math.floor(props.containerWidth) + 'px'
canvas.style.height = Math.floor(viewport.height * props.containerWidth / viewport.width) + 'px'
let renderContext = {
canvasContext: context,
viewport: viewport,
// 这里transform的六个参数,使用的是transform中的Matrix(矩阵)
// transform: [1, 0, 0, -1, 0, viewport.height]
transform: [ratio, 0, 0, ratio, 0, 0]
}
// 进行渲染
page.render(renderContext).promise.then(() => {
resolve();
}).catch(error => {
reject(error);
});
}).catch(error => {
reject(error);
});
});
}
//调用loadFile方法
onMounted(async () => {
await loadFile()
})
以上就是实现PDF文件多页展示的内容了,如果其他的小伙伴有其他的方法或者思考请批评指正