I use vue3.2
++ in my project, and now I plan to use the pdf.js library to load and preview pdf files. Below are some vite
of ts
my pitfall records! Really uncomfortable! ! !
1. Install pdf.js
Sao Rui, don't worry about the version, just cnpm and it's over
cnpm i pdfjs-dist
2. Step on the pit
After the introduction, the console reports an error, and the translation of the error content is:
Cannot read from private field
the private variable cannot be read.
Cannot read from private field
After investigation, there is pdfDoc.getPage
a problem here:
it is related to the proxy of vue3,
- Vue2 monitors data changes and reads through defineProperty.
- Vue3 changes data through proxy.
However, in the pdfjs-dist source code, an interception check is made. The content of the check is the currently passed parameters, whether there is an obj object, and if not, an error that the private variable cannot be read will be thrown directly. In the previous old project, there is no problem in writing this way: when pdfjs-dist intercepts and checks, it is an object of MaskXXX (it seems to be called this name). In vue3, when pdfjs-dist intercepts the verification, it gets a proxy object.
Correct solution: pdfDoc of pdfDoc.getPage should not use responsive writing! ! !
Refer to an article here: https://www.jianshu.com/p/1432ccd5089a
The following is the correct way of writing, (the code is slightly messy, and then changed to a component form later, the display is only for testing and explanation)
<template>
<div class="usinghelp-container">
<div class="pdf-view">
<canvas :id="`pdfCanvas${page}`" v-for="page in state.pdfPages" :key="page"></canvas>
</div>
<div class="pdf-bottom">我是操作区域</div>
</div>
</template>
<script lang="ts" setup name="usinghelp">
import {
reactive, onMounted, nextTick } from 'vue';
import {
ElMessage } from 'element-plus';
import * as PDF from "pdfjs-dist";
import workerSrc from "pdfjs-dist/build/pdf.worker.entry.js"; // 引入时如果报红线错误,不影响运行, 或在index.d.ts中声明declare
const state = reactive<any>({
pdfPath: "/pdf/华康医疗公司简介.pdf", //本地PDF文件路径放在/public中
pdfPages: '', // 页数
pdfWidth: "", // 宽度
pdfSrc: "", // 地址
pdfScale: 1.0, // 放大倍数
});
// 此处为正确写法---原来我的参数用的响应式写法,就会报错Cannot read from private field
let pdfDoc:any = ""; // 文档内容---必须使用非响应式存储
// 页面加载时
onMounted(() => {
initTableData();
});
// 初始化表格数据
const initTableData = () => {
PDF.GlobalWorkerOptions.workerSrc = workerSrc;
console.log("开始 pDF测试");
console.log(workerSrc);
console.log(PDF);
console.log("结束");
loadFile(state.pdfPath);
};
// 加载pdf文件
const loadFile = (url: string) => {
let loadingTask = PDF.getDocument(url);
loadingTask.promise.then((pdf: any) => {
console.log('PDF loaded');
debugger
pdfDoc = pdf;
state.pdfPages = pdf.numPages;
nextTick(() => {
renderPage(1); // 表示渲染第 1 页
});
});
}
// 渲染指定页面的内容
const renderPage = (num: number) => {
console.log('PDF 开始渲染',num);
console.log(pdfDoc);
pdfDoc.getPage(num).then((page: any) => {
console.log('Page loaded');
let canvas:any = document.getElementById(`pdfCanvas${
num}`);
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 = page.getViewport({
scale: state.pdfScale });
canvas.width = viewport.width * ratio;
canvas.height = viewport.height * ratio;
// canvas.style.width = viewport.width + "px";
// canvas.style.height = viewport.height + "px";
canvas.style.width = "100%";
canvas.style.height = "100%";
state.pdfWidth = viewport.width + "px";
ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
// 将 PDF 页面渲染到 canvas 上下文中
let renderContext = {
canvasContext: ctx,
viewport: viewport,
};
page.render(renderContext);
if (state.pdfPages > num) {
renderPage(num + 1);
}
});
}
</script>
<style lang="scss" scoped>
.usinghelp-container{
.pdf-view {
width: 80vw;
height: 80vh;
margin: 0 auto;
border: 1px solid #f90;
overflow: auto;
}
}
</style>