
项目中需要做一个pdfjs预览的功能
封了一个插件
<template>
<div ref="pdfBoxRef" class="pdf-box" style="max-width: 794px; margin: 0 auto">
<div class="pdf-center-box">
<div class="post-flex flex-between">
<div>
<el-button class="el-icon-zoom-in" title="放大" type="text" :disabled="btnDisabled" @click="toScale(5)">
放大
</el-button>
<el-button class="el-icon-refresh" title="重置" type="text" :disabled="btnDisabled" @click="toScale(0)">
重置
</el-button>
<el-button class="el-icon-zoom-out" title="缩小" type="text" :disabled="btnDisabled" @click="toScale(-5)">
缩小
</el-button>
</div>
<el-button v-show="download" class="el-icon-download" type="text" size="mini" @click="handleDownload">
下载
</el-button>
</div>
<div ref="contentRef" class="left">
<div ref="pdfViewerRef" class="pdfView"></div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import * as PDFJS from "pdfjs-dist";
PDFJS.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/build/pdf.worker';
// PDFJS.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/build/pdf.worker.min.js';
const props = defineProps({
url: {
type: String,
default: "",
},
download: {
type: Boolean,
default: false,
},
loading: {
type: Boolean,
default: false,
},
});
const pdfLoading = ref(true)
const pdfLoadingPercent = ref(0)
const scale = ref(100)
const btnDisabled = computed(() => {
return pdfLoading.value || props.loading
})
const loadNewPdf = (url) => {
unmountPdf();
setTimeout(() => {
hanle(url);
}, 200); // 等待一小段时间再加载新的 PDF,防止渲染冲突
};
watch(() => props.url, (val) => {
if (val) {
nextTick(()=>{
loadNewPdf(val);
})
}
},{immediate: true})
const pdfViewerRef = ref()
const unmountPdf = () => {
const pdfContainer = pdfViewerRef;
if (pdfContainer) {
pdfContainer.value.innerHTML = "";
}
}
const pdfBoxRef = ref()
const renderPDF = (pdf, i, id) =>{
pdf.getPage(i).then((page) => {
const [pageWidth] = page.view.slice(2); // 从索引 2 开始提取
const maxWidth = Number(pdfBoxRef.value.style.maxWidth.split("px")[0]);
const viewport = page.getViewport({
// 计算默认缩放比
scale: maxWidth / pageWidth,
rotation: 0, // 不旋转
dontFlip: false, // 允许翻转(默认)
});
// 准备用于渲染的 canvas 元素
const canvas = pdfViewerRef.value.querySelector(`.${id}`);
const context = canvas.getContext("2d");
canvas.width = viewport.width;
canvas.height = viewport.height;
// 将 PDF 页面渲染到 canvas 上下文中
const renderContext = {
canvasContext: context,
viewport: viewport,
};
page.render(renderContext);
});
}
const handleDownload =() =>{
window.open(props.url);
}
const toScale = (num) => {
if (num === 0) {
scale.value = 100;
} else {
scale.value += num;
}
let domArray = pdfViewerRef.value.querySelectorAll(".pdfClass");
domArray.forEach((item) => {
let widthTemp = item.width;
let heightTemp = item.height;
item.style.width = parseInt(widthTemp) * (scale.value / 100) + "px";
item.style.height = parseInt(heightTemp) * (scale.value / 100) + "px";
});
}
const hanle = (url) => {
pdfLoadingPercent.value = 0;
pdfLoading.value = true;
const loadingTask = PDFJS.getDocument({
url,
rangeChunkSize: 65536, // 64KB 分块加载
disableRange: false, // 确保启用 Range
disableStream: false, // 允许流式加载
});
loadingTask.onProgress = ({ loaded, total }) => {
pdfLoadingPercent.value = Math.min(100, parseFloat((loaded / total * 100).toFixed(2)));
};
loadingTask.promise.then((pdf) => {
// 加载完毕
pdfLoading.value = false;
const idTemplate = "cw-pdf-";
const pageNum = pdf.numPages;
// 根据页码创建画布
createSeriesCanvas(pageNum, idTemplate);
// 将pdf渲染到画布上去
for (let i = 1; i <= pageNum; i++) {
renderPDF(pdf, i, idTemplate + i);
}
});
}
const createPdfContainer = (id, className) => {
const pdfContainer = pdfViewerRef.value;
const canvasNew = document.createElement("canvas");
canvasNew.classList.add(id);
canvasNew.classList.add(className);
pdfContainer.appendChild(canvasNew);
emits("ok");
}
const createSeriesCanvas = (num, template) => {
var id = "";
for (var j = 1; j <= num; j++) {
id = template + j;
createPdfContainer(id, "pdfClass");
}
}
const emits = defineEmits(["ok"]);
</script>
<style lang="scss" scoped>
.flex-between {
display: flex;
justify-content: space-between;
padding: 5px 40px;
box-sizing: border-box;
}
.pdf-box {
position: relative;
width: 100%;
height: 100%;
.pdf-center-box {
overflow-x: auto;
width: 100%;
padding: 10px;
.pdfView {
overflow: hidden;
box-shadow: 0 0 6px 2px rgb(194, 194, 194);
overflow-x: auto;
.pdfClass {
margin-bottom: 10px !important;
}
}
&:hover .post-flex {
display: block;
}
.post-flex {
display: none;
position: absolute;
width: 665px;
left: 10px;
top: 10px;
background: #00000066;
z-index: 9999999;
&::v-deep .el-button--text {
color: #fff;
margin: 0 10px;
}
}
}
}
.pdf {
margin: 5px 0;
box-shadow: 0 0 6px 2px rgb(194, 194, 194);
}
</style>
遇到的坑是开始只能支持外部引用pdf.worker.min.js,但是速度非常慢,并且有时候半天打不开,

于是想到用本地引用,需要在index.html中挂载,在public文件夹中创建文件,并且将外部链接中代码的拷入文件中
<script src="/public/pdf.worker.min.js"></script>

5653

被折叠的 条评论
为什么被折叠?



