前言:最近和小伙伴们一起合作完成一个面试推送系统的书写,其中一个功能就是渲染PDF文件,展示用户上传的面经,干了整整一周,终于实现了这个功能,现在将自己实现的过程分享给大家.
1.pdfjs-dist展示PDF文件的原理解释
pdfjs-dist展示pdf文档的原理,实际上是将pdf中的内容渲染到解析,然后渲染到 canvas 中进行展示,因此我们使用pdfjs渲染出来的pdf文件,实际上是一张张canvas图片。
2.安装pdfjs-dist

打开VScode,使用ctl+`打开控制台,输入:npm i pdfjs-dist 安装pdfjs-dist
3. 搭建基础的页面代码
话不多说,上代码:
- <template>
- <div class="interviewVideo_main" id="videoContainer">
- <!--此处根据pdf的页数动态生成相应数量的canvas画布-->
- <canvas
- v-for="pageIndex in pdfPages"
- :id="`pdf-canvas-` + pageIndex"
- :key="pageIndex"
- style="display: block"
- ></canvas>
- </div>
- </template>
4.使用Vue3语法实现PDF文件的多页展示
4.1引入ref、pdfjs-dist
- import { ref, reactive, onMounted, nextTick } from "vue";
- //注意引入的写法
- import * as pdfjsLib from "pdfjs-dist/build/pdf";
4.2将会用到的数据声明为响应式
- let pdfDoc = reactive({}); // 保存加载的pdf文件流
- let pdfPages = ref(0); // pdf文件的页数
- //pdf文件的链接
- let pdfUrl = ref("需要展示的文件名");
- let pdfScale = ref(1.0); // 缩放比例
4.3定义获取pdf文档流与pdf文件的页数的方法:loadFile
''
//获取pdf文档流与pdf文件的页数 const loadFile = async (url) => { //注意我的pdfjs-dist的版本是3.9.179,其他的版本需要更换版本号,不然运行时会报版本不匹配的错 //外部链接引入,存在安全性问题 //pdfjsLib.GlobalWorkerOptions.workerSrc = //"https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.9.179/pdf.worker.min.js"; //内部链接引入 pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.min.js"; const loadingTask = pdfjsLib.getDocument(url); loadingTask.promise.then((pdf) => { console.log(pdf); pdfDoc = pdf; //获取pdf文档流 pdfPages.value = pdf.numPages;//获取pdf文件的页数 nextTick(() => { renderPage(1); }); }); };运行
4.4定义渲染pdf文件的方法:renderPage
''
const renderPage = (num) => { pdfDoc.getPage(num).then((page) => { const canvasId = "pdf-canvas-" + num; const canvas = document.getElementById(canvasId); const ctx = canvas.getContext("2d"); const dpr = window.devicePixelRatio || 1; const bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; const ratio = dpr / bsr; const viewport = page.getViewport({ scale: pdfScale.value }); canvas.width = viewport.width * ratio; canvas.height = viewport.height * ratio; canvas.style.width = viewport.width + "px"; canvas.style.height = viewport.height + "px"; ctx.setTransform(ratio, 0, 0, ratio, 0, 0); const renderContext = { canvasContext: ctx, viewport: viewport, }; page.render(renderContext); if (num < pdfPages.value) { renderPage(num + 1); } }); };运行
4.5在onMounted钩子中调用loadFile方法
- //调用loadFile方法
- onMounted( () => {
- loadFile(pdfUrl.value);
- });
5完整代码实现:
- <template>
- <div class="interviewVideo_main" id="videoContainer">
- <!--此处根据pdf的页数动态生成相应数量的canvas画布-->
- <canvas
- v-for="pageIndex in pdfPages"
- :id="`pdf-canvas-` + pageIndex"
- :key="pageIndex"
- style="display: block"
- ></canvas>
- </div>
- </template>
- <script setup>
- import { ref } from "vue";
- import * as pdfjsLib from "pdfjs-dist/build/pdf";
- let pdfDoc = reactive({}); // 保存加载的pdf文件流
- let pdfPages = ref(0); // pdf文件的页数
- let pdfUrl = ref(""); //pdf文件的链接
- let pdfScale = ref(1.0); // 缩放比例
- //调用loadFile方法
- onMounted(() => {
- loadFile(pdfUrl.value);
- });
- //获取pdf文档流与pdf文件的页数
- const loadFile = async (url) => {
- pdfjsLib.GlobalWorkerOptions.workerSrc =
- "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.9.179/pdf.worker.min.js";
- const loadingTask = pdfjsLib.getDocument(url);
- loadingTask.promise.then((pdf) => {
- console.log(pdf);
- pdfDoc = pdf;
- pdfPages.value = pdf.numPages;
- nextTick(() => {
- renderPage(1);
- });
- });
- };
- //渲染pdf文件
- const renderPage = (num) => {
- pdfDoc.getPage(num).then((page) => {
- const canvasId = "pdf-canvas-" + num;
- const canvas = document.getElementById(canvasId);
- const ctx = canvas.getContext("2d");
- const dpr = window.devicePixelRatio || 1;
- const bsr =
- ctx.webkitBackingStorePixelRatio ||
- ctx.mozBackingStorePixelRatio ||
- ctx.msBackingStorePixelRatio ||
- ctx.oBackingStorePixelRatio ||
- ctx.backingStorePixelRatio ||
- 1;
- const ratio = dpr / bsr;
- const viewport = page.getViewport({ scale: pdfScale.value });
- canvas.width = viewport.width * ratio;
- canvas.height = viewport.height * ratio;
- canvas.style.width = viewport.width + "px";
- canvas.style.height = viewport.height + "px";
- ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
- const renderContext = {
- canvasContext: ctx,
- viewport: viewport,
- };
- page.render(renderContext);
- if (num < pdfPages.value) {
- renderPage(num + 1);
- }
- });
- };
- </script>
- <style>
- #videoContainer {
- height: 842px;
- }
- </style>
以上就是实现PDF文件多页展示的内容了,如果其他的小伙伴有其他的方法或者思考请批评指正
6.使用本地文件
如果直接引用本地PDF文件,浏览器会报错:network.js:101 Not allowed to load local resource
原因如下:
浏览器的安全策略禁止直接加载本地文件。这是浏览器的安全限制,旨在防止恶意代码读取用户的本地文件系统。
处理方法:
1.将本地的PDF文件,放在public文件夹下,然后直接引用文件链接即可


2.放在assets文件下,使用import引入项目

我采用的方法是配合后端,将所有的PDF文件存放在阿里云中,借助第三方增加安全性,如果在使用阿里云存放后,报错:

可以依据阿里云官方提供的配置文件进行配置,链接如下:
阿里云文件跨域配置