vue基于vue-pdf实现pdf预览
1、vue-pdf插件正常渲染后控制台报错
解决方式:node_modules文件夹修改vue-pdf中pdfjsWrapper.js文件
2、初步实现
<template>
<div class="pdf-container">
<div class="page-tool">
文件名称扩展
<div class="page-tool-fixed" v-if="showTool">
<span class="scale-icon" @click="prePage"><i class="el-icon-arrow-left"></i></span>
<span class="scale-icon" @click="clock"><i class="el-icon-refresh-right"></i></span>
<span class="scale-icon" @click="zoomOut"><i class="el-icon-zoom-out"></i></span>
<div class="tool-input"><el-input-number :precision="0" :min="0" :max="pageTotalNum" :controls="false" @change="handleChange" v-model.number="pageNum"></el-input-number>/{{pageTotalNum}} </div>
<span class="scale-icon" @click="zoomIn"><i class="el-icon-zoom-in"></i></span>
<span class="scale-icon" @click="counterClock"><i class="el-icon-refresh-left"></i></span>
<span class="scale-icon" @click="nextPage"><i class="el-icon-arrow-right"></i></span>
</div>
</div>
<div v-if="pdfLoadState" :style="{width:scale+'%'}">
<Pdf
class="page-main"
:page="pageNum"
:rotate="pageRotate"
@num-pages="pageTotalNum = $event"
ref="pdf"
:src="url">
</Pdf>
</div>
<el-result class="load-err" v-else icon="error" title="错误提示" subTitle="PDF文档加载失败,请检查文件完整性"></el-result>
</div>
</template>
<script>
import Pdf from 'vue-pdf'
import CMapReaderFactory from 'vue-pdf/src/CMapReaderFactory.js';
let ob;
let div;
export default {
components:{
Pdf
},
data(){
return {
url:"",
pageNum:1,
pageTotalNum: 1,
pageRotate: 0,
scale:80,
pdfLoadState:true,
showTool:false,
watermarkDom:0,
}
},
created(){
this.getNumPages('/public/text.pdf')
},
mounted(){
// 创建MutationObserver 来进行监控
ob = new MutationObserver((records) => {
for(let record of records){
for (const dom of record.removedNodes) {
if (dom === div) {
this.watermarkDom++; // 删除节点的时候更新依赖
return;
}
}
if (record.target === div) {
this.watermarkDom++; // 修改属性的时候更新依赖
return;
}
}
});
// 创建好监听器之后,告诉监听器需要监听的元素
const parent=this.$refs.pdf.$el
ob.observe(parent, {
// 监听的时候需要加一些配置
childList: true, // 元素内容有没有发生变化
attributes: true, // 元素本身的属性有没有发生变化
subtree: true, // 监控整个子树,包含整个子元素
});
},
destroyed() {
ob && ob.disconnect(); // 取消监听
div=null
},
watch:{
watermarkDom(){
this.setWatermark()
console.log('暂不支持修改界面元素')
}
},
methods:{
setWatermark(){
if (div) {
div.remove();
}
const parent=this.$refs.pdf
const waterCanvas=document.createElement('canvas')
const waterCtx=waterCanvas.getContext('2d')
// 在画布上输出文本之前,检查字体的宽度
const { width } = waterCtx.measureText('测试水印');
const canvasSize = Math.max(300, width)
waterCanvas.width = canvasSize;
waterCanvas.height = canvasSize;
waterCtx.translate(waterCanvas.width / 2, waterCanvas.height / 2);
// 旋转 45 度让文字变倾斜
waterCtx.rotate((Math.PI / 180) * -45);
waterCtx.font = '40px Microsoft Yahei';
waterCtx.fillStyle = 'rgba(0, 0, 0, 0.3)';
waterCtx.textAlign='center'
waterCtx.textBaseline = 'middle';
waterCtx.fillText('测试水印',0,0)
let imgSrc = waterCanvas.toDataURL("image/png");
div = document.createElement('div');
// 背景设置为 base64 的图片
div.style.backgroundImage = `url(${imgSrc})`;
// 背景的大小设置为 styleSize
div.style.backgroundSize = `${canvasSize}px ${canvasSize}px`;
// 重复方式设置为 repeat
div.style.backgroundRepeat = 'repeat';
// 设置子元素与父元素四个方向的间隔(这里设置为 0 的效果同宽高设置 100%)
div.style.inset = 0;
div.style.zIndex = 9998;
// 设置绝对定位
div.style.position = 'absolute';
// 设置点击穿漏,防止底部元素失去鼠标事件的交互
div.style.pointerEvents = 'none';
parent.$el.appendChild(div)
},
getNumPages(url) {
let loadingTask = Pdf.createLoadingTask({url,CMapReaderFactory})
loadingTask.promise.then(pdf => {
this.url=loadingTask
this.numPages = pdf.numPages
this.showTool=true
this.setWatermark()
}).catch((err) => {
console.error(err)
console.error('pdf加载失败')
this.pdfLoadState=false
})
},
toTop(){
window.scrollTo(0, 0)
},
zoomIn() {
let scale=this.scale +5
this.scale = scale>100?100:scale
},
//缩小
zoomOut() {
let scale=this.scale -5
this.scale = scale<60?60:scale
},
// 上一页函数,
prePage() {
let page = this.pageNum
page = page > 1 ? page - 1 : this.pageTotalNum
this.pageNum = page
this.toTop()
},
// 下一页函数
nextPage() {
let page = this.pageNum
page = page < this.pageTotalNum ? page + 1 : 1
this.pageNum = page
this.toTop()
},
handleChange(){
this.toTop()
},
// 页面顺时针翻转90度。
clock() {
this.pageRotate += 90
},
// 页面逆时针翻转90度。
counterClock() {
this.pageRotate -= 90
}
}
}
</script>
<style lang="scss">
.pdf-container{
display: flex;
justify-content: center;
background-color: #e9e9e9;
overflow: hidden;
.page-tool {
position: fixed;
left: 0;
top: 0;
z-index: 9999;
background-color: #fafafa;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 20px;
width: 100%;
border-bottom: 1px solid #e9e9e9;
}
.page-tool-fixed{
display: flex;
justify-content: center;
position: fixed;
left: 50%;
bottom: 50px;
transform: translateX(-50%);
z-index: 1050;
height: 44px;
line-height: 44px;
background-color: #e9e9e9;
font-size: 16px;
font-weight: 500;
border-radius: 20px;
opacity: 0.8;
user-select: none;
.scale-icon{
font-size: 25px;
margin: 0 10px;
cursor: pointer;
}
.tool-input{
display: flex;
align-items: center;
.el-input-number{
width: 45px;
.el-input__inner {
padding: 0 10px;
}
}
}
}
.page-main{
margin: 10px 20px;
position: absolute;
top: 40px;
left: 0;
}
.load-err{
position: absolute;
top: 40px;
left: 0;
width: 100%;
}
}
</style>
实现效果: