vue3 实现pdf预览
需要下载pdfjs-dist
<template>
<a-modal class="fill-modal" v-model:open="state.visible" :title="state.modalTitle" width="50%" @cancel="handleCancel">
<div class="preview-btns-posi">
<a-button type="primary" @click="exportBtn" :loading="state.downLoading">下载</a-button>
<a-button @click="handleCancel" type="primary">返回</a-button>
</div>
<div class="interviewVideo_main" id="videoContainer">
<!--此处根据pdf的页数动态生成相应数量的canvas画布-->
<canvas v-show="state.show" v-for="pageIndex in pdfPages" :id="`pdf-canvas-` + pageIndex" :key="pageIndex"
style="display: block;width:100%;" class="canvas"></canvas>
</div>
<template #footer></template>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, nextTick } from "vue";
import * as pdfjsLib from "pdfjs-dist/build/pdf.js";
import * as workerSrc from 'pdfjs-dist/build/pdf.worker.min.js'
import { message } from "ant-design-vue";
import { downloadBlobAsync } from "@/lib/tool";
let pdfPages = ref(0); // pdf文件的页数
let pdfDoc: any = reactive({})
let pdfScale = ref(1.0); // 缩放比例
const state: any = reactive({
visible: false,
downLoading: false,
modalTitle: '预览文件',
show: false
})
const props = defineProps<{
file: {
previewPath: string,
originalFileName: string,
path: string,
}
}>()
//调用loadFile方法
//获取pdf文档流与pdf文件的页数
const loadFile = async (url: string) => {
try {
pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;
const loadingTask = pdfjsLib.getDocument(url);
loadingTask.promise.then((pdf: any) => {
state.show = true;
pdfDoc = pdf;
pdfPages.value = pdf.numPages;
nextTick(() => {
renderPage(1);
});
}).catch((err: any) => {
console.error(err);
pdfDoc = null
state.show = false
});
} catch (error) {
console.error(error)
}
};
//渲染pdf文件
const renderPage = (num: number) => {
pdfDoc?.getPage(num).then((page: any) => {
const canvasId = "pdf-canvas-" + num;
const canvas = <any>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);
}
});
};
function openModal() {
state.visible = true;
nextTick(() => {
loadFile(props.file.previewPath);
})
}
function handleCancel() {
state.visible = false;
}
async function exportBtn() {
try {
state.downLoading = true
if (!props.file?.path) {
message.warning(`无地址,可供下载`)
return;
}
await downloadBlobAsync(props.file?.path, props.file?.originalFileName, true)
} catch (error: any) {
message.error(error)
} finally {
state.downLoading = false
}
}
defineExpose({
openModal
})
</script>
<style>
#videoContainer {
height: 500px;
width: 100%;
overflow: auto;
.canvas {
width: 80% !important;
margin: 0 auto;
}
}
.preview-btns-posi {
position: absolute;
top: 10px;
right: 50px;
}
</style>
/**下载文件 */
export const downloadBlobAsync = (blob: Blob | string, fileName: string, isUrl = false) => {
return new Promise<void>((resolve, reject) => {
try {
//对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
//IE10以上支持blob但是依然不支持download
if ('download' in document.createElement('a')) {
//支持a标签download的浏览器
const link = document.createElement('a'); //创建a标签
link.download = fileName; //a标签添加属性
link.style.display = 'none';
link.href = isUrl ? blob as string : URL.createObjectURL(blob as Blob);
document.body.appendChild(link);
link.click(); //执行下载
URL.revokeObjectURL(link.href); //释放url
document.body.removeChild(link); //释放标签
} else {
//其他浏览器
(navigator as any)?.msSaveBlob(blob, fileName);
}
} catch (error) {
console.log(error)
reject(error);
} finally {
setTimeout(() => {
resolve()
}, 500)
}
})
};