PDF.js 提供了pdfjs-dist这个包,用于通过 npm 安装使用。这里使用 canvas 渲染 PDF。
官方示例:Examples (mozilla.github.io) ,但是官方示例并没有明确给出在 Vite 中如何加载pdf.worker.js。查阅 Vite 文档 功能 | Vite 官方中文文档 (vitejs.dev),发现 Vite 支持以 url 形式导入某个 js 文件。
<script setup lang="ts">
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist";
// 显式加载资源为一个 URL
import workerUrl from "pdfjs-dist/build/pdf.worker.js?url";
const route = useRoute();
const canvasContainer = ref<HTMLElement | null>(null);
onMounted(async () => {
// 配置 workerSrc 为 pdf.worker.js 的地址,这一步是必须的
GlobalWorkerOptions.workerSrc = workerUrl;
// 从 url 中读取 pdf 文件的 url,也可以使用其他方式
const file = route.query.file;
if (!file || typeof file !== "string") throw new Error("file is null");
const pdf = await getDocument(file).promise;
if (!canvasContainer.value) throw new Error("canvasContainer is null");
// 设置倍数为 2,我发现这样较为清晰。也可以调整为其他值。
const scale = 2;
// 开始循环解析每一页
for (let i = 1; i <= pdf.numPages; i++) {
const canvas = document.createElement("canvas");
const page = await pdf.getPage(i);
const viewport = page.getViewport({ scale });
const context = canvas.getContext("2d");
if (!context) throw new Error("context is null");
// 指定 canvas 的尺寸为 pdf 的尺寸
canvas.height = viewport.height;
canvas.width = viewport.width;
// 开始渲染
await page.render({
canvasContext: context,
viewport: viewport,
}).promise;
// 把 canvas 加入到 DOM 里
canvasContainer.value.appendChild(canvas);
}
});
</script>
<template>
<div ref="canvasContainer" class="canvas-container"></div>
</template>
<style scoped>
.canvas-container {
width: 100%;
}
.canvas-container :deep(canvas) {
width: 100%;
display: block;
}
</style>
在本例中,我直接使用 canvas 节点来绘制每一页的 PDF,然而当文件的页数过大时,会在 DOM 中生成大量的 canvas 节点。这可能会导致性能问题。可选的解决方案是,在每页渲染完成后,将 canvas 中的内容转换为图片。