您可以存储和使用 PDFDocumentProxy/PDFPageProxy 对象(来自 pdf.js)作为 Vue 组件的成员吗?

Con*_*nje 1 pdf.js vue.js

我希望将一些文档/页面加载逻辑封装在 Vue 组件中,但我在让它工作时遇到了麻烦。这是我尝试过的。(如果相关的话,我使用 Vite + Vue + TS 和"pdfjs-dist": "^2.14.305", "vue": "^3.2.25"。)

首先,我有一个名为 PDFDocument 的组件。它传递 PDF URL 和比例作为属性,并处理获取文档和加载页面。

// PDFDocument.vue
<template>
<div class="pdf-document">
    <PDFPage v-for="page in pages" v-bind="{page, scale}" :key="page.pageNumber"/>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import * as pdfjsLib from 'pdfjs-dist';
import PDFPage from './PDFPage.vue';
pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.js";

export default defineComponent({
    props: {
        url: { type: String, required: true },
        scale: { type: Number, required: true },
    },
    data() {
        let pdf: pdfjsLib.PDFDocumentProxy | undefined;
        let pages: pdfjsLib.PDFPageProxy[] = [];
        return { pdf, pages };
    },
    beforeMount() {
        let loadingTask = pdfjsLib.getDocument(this.url);
        loadingTask.promise.then((pdf) => {
            this.pdf = pdf;
            const promises = [];
            for (let i = 1; i <= pdf.numPages; i++) {
                promises.push(pdf.getPage(i));
            }
            Promise.all(promises).then(pages => {
                this.pages = pages;
                console.log(this.pages);
            });
        });
    },
    components: { PDFPage }
})
</script>
Run Code Online (Sandbox Code Playgroud)

这似乎有效,但我已经遇到了第一个问题。如果我尝试使用this.pdf.getPage(i)而不是pdf.getPage(i),则会收到错误:Uncaught (in promise) TypeError: Cannot read from private field。但pdf现在只要使用修复即可,所以没关系。

然后我有一个 PDFPage 组件,用于处理设置页面的画布并PDFPageProxy在其上渲染。

// PDFPage.vue
<template>
<canvas
    class="pdf-page"
    :width="width"
    :height="height"
    :style="canvasStyle"
></canvas>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import * as pdfjsLib from 'pdfjs-dist';
pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.js";

export default defineComponent({
    props: {
        page: {type: pdfjsLib.PDFPageProxy, required: true},
        scale: {type: Number, required: true},
    },
    data() {
        let viewport: pdfjsLib.PageViewport | undefined;
        let renderTask: pdfjsLib.RenderTask | undefined;
        return { viewport, renderTask }
    },
    computed: {
        width() { if (!this.viewport) return 0; return this.viewport.width; },
        height() { if (!this.viewport) return 0; return this.viewport.height; },
        canvasStyle() {
            const {width: actualWidth, height: actualHeight} = this.actualSizeViewport;
            const pxRatio = window.devicePixelRatio || 1;
            const [pxWidth, pxHeight] = [actualWidth, actualHeight]
                .map(dim => Math.ceil(dim / pxRatio));
            return `width: ${pxWidth}px; height: ${pxHeight}px;`
        },
        actualSizeViewport() {
            return (this.viewport as pdfjsLib.PageViewport).clone({scale: this.scale});
        },
    },
    methods: {
        drawPage() {
            if (this.renderTask) return;
            const {viewport} = this;
            const canvasContext = this.$el.getContext('2d');
            const renderContext = {canvasContext, viewport};
            this.renderTask = this.page.render(renderContext);
            (this.renderTask as pdfjsLib.RenderTask).promise.then(
                () => this.$emit('rendered', this.page)
            );
        }
    },
    created() {
        this.viewport = this.page.getViewport(this.scale);
    },
    mounted() {
        this.drawPage();
    }
})
</script>
Run Code Online (Sandbox Code Playgroud)

在这里,我在尝试执行此操作时遇到错误Uncaught (in promise) TypeError: Cannot read from private field(或有时) ,我认为这是一个问题,因为我正在使用.Cannot write to private fieldthis.renderTask = this.page.render(renderContext)this.page

有谁知道如何解决这个问题?Proxy我觉得这可能与这些对象声称是工作线程的代理这一事实有关,而我可能不尊重这一点?

Con*_*nje 6

经过一番挖掘,我想我找到了罪魁祸首。我不确定这是 PDF.js 的东西还是 Vue 3 的东西,但this.pdfthis.page对象是Proxys,而不是对象本身。toRaw从 Vue导入并使用toRaw(this.pdf).getPage(i)ortoRaw(this.page).render(renderContext)似乎已经解决了问题。(参考:/sf/answers/4956362211/。

(PS 另外,this.page.getViewport在 PDFPage 组件中也需要this.page.getViewport({scale = this.scale})渲染才能工作!)