第一种方式:使用vue-pdf-embed和vue3-pdfjs
使用的插件有:
npm i vue-pdf-embed
npm i vue3-pdfjs
html部分:
<div ref="preRef" v-loading="loading" class="pdf-preview"><div v-if="pdfState.source" class="pdf-wrap"><VuePdfEmbedv-for="item in pdfState.numPages":key="item":source="pdfState.source":style="pdfState.scale"class="vue-pdf-embed":page="item"/></div><van-empty v-if="loadError" image="error" description="PDF加载出错了..." /></div>
js部分:
// 引入两个插件相关的
import VuePdfEmbed from 'vue-pdf-embed';
import { createLoadingTask } from 'vue3-pdfjs';
// 以上涉及的参数
const pdfState = reactive({source: '', // 预览pdf文件地址pageNum: 1, // 当前页面scale: 1, // 缩放比例numPages: 0, // 总页数width: '400px', // 宽度
});
const preRef = ref();
const detail = ref({});//返回的数据
const loading = ref(true);
const loadError = ref(false);// 方法
// 接口返回的数据
function getDetail() {baseInfoGet({ id: route.currentRoute.value.query.id }).then((res) => {detail.value = res.data;const url = safeJSONParse(res.data.fileUrl)?.[0].url || '';pdfState.source = url;console.log('预览地址:', url);if (!url) return;setTimeout(() => {pdfState.width = getComputedStyle(preRef.value)?.width;console.log(pdfState.width);loadingPdf(url);}, 0.5 * 1000);});
}
// 加载pdf的方法
function loadingPdf(url) {const loadingTask = createLoadingTask(url);loadingTask.promise.then((pdf) => {pdfState.numPages = pdf.numPages;loading.value = false;}).catch(() => {loading.value = false;loadError.value = true;});
}
我一开始使用的时第一种方法,然后测试之后发现苹果手机会显示pdf加载出错了,安卓手机可以正常显示,于是换成了第二种方法。
第二种方式使用pdfjs-dist,苹果手机加载失败需使用版本2.2.228
npm i pdfjs-dist
html部分:
<div class="pdf-viewer"><template v-for="item in pageNum" :key="item"><canvas :id="`pdf-canvas-${item}`" class="pdf-page" /></template><van-emptyv-if="loadError"image="error"description="PDF加载出错了..."/></div>
js部分:
// 引入插件相关的参数
import * as pdfjs from 'pdfjs-dist';
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry';
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;// html部分涉及的参数
const loadError = ref(false);
const detail = ref({});
let pdfDoc = null; // 一定不能使用响应式的数据,会报错Cannot read from private field---pdf.js
const pageNum = ref(0);
// 处理接口返回的pdf的url
function getDetail() {baseInfoGet({ id: route.currentRoute.value.query.id }).then((res) => {detail.value = res.data;const url = safeJSONParse(res.data.fileUrl)?.[0].url || '';showLoadingToast({message: '加载中...',forbidClick: true,});console.log('预览地址:', url);if (!url) return;loadingPdf(url);});
}
//加载pdf
function loadingPdf(url) {const loadingTask = pdfjs.getDocument(url);loadingTask.promise.then((pdf) => {pdfDoc = pdf;pageNum.value = pdf.numPages;nextTick(() => {renderPage();});}).catch(() => {closeToast();loadError.value = true;});
}
// 渲染pdf
function renderPage(num = 1) {pdfDoc.getPage(num).then((page) => {const canvas = document.getElementById(`pdf-canvas-${num}`);const ctx = canvas.getContext('2d');const scale = 1.5;const viewport = page.getViewport({ scale });// 画布大小,默认值是width:300px,height:150pxcanvas.height = viewport.height;canvas.width = viewport.width;// 画布的dom大小, 设置移动端,宽度设置铺满整个屏幕const { clientWidth } = document.body;// 减去2rem使用因为我的页面左右加了paddingcanvas.style.width = `calc(${clientWidth}px - 2rem)`;// 根据pdf每页的宽高比例设置canvas的高度canvas.style.height = `${clientWidth * (viewport.height / viewport.width)}px`;canvas.height = viewport.height;canvas.width = viewport.width;page.render({canvasContext: ctx,viewport,});if (num < pageNum.value) {renderPage(num + 1);} else {closeToast();}});
}
用了第二种插件后,苹果手机还是加载不出来,后面查到因为pdfjs-dist有时候会出现部分手机比如iphone6和iphone8渲染不出pdf问题
解决办法:
将pdfjs-dist版本改为2.2.228
npm i pdfjs-dist@2.2.228
然后就加载出来了,最后在各个环境测试的时候又发现,微信小程序里面打开这个模块,pdf还是没加载出来,console之后发现请求401,报错信息是登陆访问超时,发现pdfjs加载pdf时没有携带token
遂,在加载url时添加token即可
pdfjs加载pdf时携带token
//加载pdf
function loadingPdf(url) {const afterUrl = {url,httpHeaders: {token: `Bearer-${localStorage.getItem('token')}`,},};const loadingTask = pdfjs.getDocument(afterUrl );loadingTask.promise.then((pdf) => {pdfDoc = pdf;pageNum.value = pdf.numPages;nextTick(() => {renderPage();});}).catch(() => {closeToast();loadError.value = true;});
}
添加之后就加载出来了