[Vue] Use pdf.js in vue3.2 to step on the pit: Cannot read from private field---pdf.js detailed explanation

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 viteof tsmy 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

insert image description here

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 fieldthe private variable cannot be read.

Cannot read from private field

After investigation, there is pdfDoc.getPagea 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>

Guess you like

Origin blog.csdn.net/weixin_42960907/article/details/127366807
Recommended