在vue项目中,有的功能需要对pdf进行操作,比如:预览、下载、打印等,但是没有组件库有pdf的插件,需要安装下载专门的pdf插件,这里对pdf操作做了整合,分享给大家。
示例使用的是vue-pdf组件库,如果大家有更好的插件可以进行交流学习~
话不多说,上代码!!!(vue基础的代码就不过多展示了)
一、安装插件
npm i vue-pdf
插件的github地址: https://github.com/FranckFreiburger/vue-pdf
二、在公共组件库新建PdfView文件夹,这里放封装好的组件,代码如下
<template>
<div class="pdfView">
<div class="show">
<!--分页显示-->
<pdf
ref="pdf"
:src="pdfUrl"
:page="pageNum"
:rotate="pageRotate"
@password="password"
@progress="loadedRatio = $event"
@loaded="onLoadSuccess"
@page-loaded="pageLoaded($event)"
@num-pages="pageTotalNum = $event"
@error="pdfError($event)"
@link-clicked="page = $event"
>
</pdf>
<!--整页显示-->
<!-- <pdf
v-loading="loading"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
v-for="i in numPages"
:key="i"
:src="pdfUrl"
:page="i"
@error="pdfError($event)"
ref="pdf"
></pdf> -->
</div>
<div class="pdf_footer">
<div class="info">
<div>当前页数/总页数:{{ pageNum }}/{{ pageTotalNum }}</div>
<!-- <div>进度:{{ loadedRatio }}</div> -->
<!-- <div>页面加载成功: {{ curPageNum }}</div> -->
</div>
<div class="operate">
<el-button-group>
<el-button type="primary" icon="el-icon-arrow-left" style="border-radius: 30px 0 0 30px" @click.stop="prePage">上一页</el-button>
<el-button type="primary" @click.stop="nextPage" style="border-radius: 0 30px 30px 0">下一页<i class="el-icon-arrow-right el-icon--right"></i></el-button>
</el-button-group>
<el-button-group>
<el-button type="primary" style="border-radius: 30px 0 0 30px" @click="scaleD">放大</el-button>
<el-button type="primary" style="border-radius: 0 30px 30px 0" @click="scaleX">缩小</el-button>
</el-button-group>
<!-- <el-button type="primary" @click="fileDownload(pdfUrl, 'pdf文件')">
下载
<i class="el-icon-download"></i>
</el-button> -->
</div>
</div>
</div>
</template>
<script>
import pdf from "vue-pdf";
export default {
name: "vue_pdf_preview",
props: {
// 当前pdf路径
pdfUrl: {
type: String,
default: "",
},
},
components: {
pdf,
},
data() {
return {
// 总页数
pageTotalNum: 1,
// 当前页数
pageNum: 1,
// 加载进度
loadedRatio: 0,
// 页面加载完成
curPageNum: 0,
// 放大系数 默认百分百
scale: 100,
// 旋转角度 ‘90’的倍数才有效
pageRotate: 0,
// 单击内部链接时触发 (目前我没有遇到使用场景)
page: 0,
// 当前页数
numPages: 1,
// 预览路径
localUrl: '',
loading: true
};
},
watch: {
pdfUrl: {
handler(newVal,oldVal) {
this.localUrl = "";
this.localUrl = newVal;
let loadingTask = pdf.createLoadingTask(this.localUrl);
loadingTask.promise.then(pdf => {
this.numPages = pdf.numPages;
this.loading = false;
console.log('this.numPages', this.numPages)
}).catch((err) => {
console.error('pdf加载失败', err)
})
},
immediate: true
}
},
computed: {},
created() {},
mounted() {},
methods: {
onLoadSuccess(pdf) {
// PDF加载成功后,可以将初始页码设置为第一页
this.pageNum = 1;
},
//下载PDF
fileDownload(data, fileName) {
let blob = new Blob([data], {
//type类型后端返回来的数据中会有,根据自己实际进行修改
type: "application/pdf",
});
let filename = fileName || "pdf.pdf";
if (typeof window.navigator.msSaveBlob !== "undefined") {
window.navigator.msSaveBlob(blob, filename);
} else {
var blobURL = URL.createObjectURL(blob);
// 创建隐藏<a>标签进行下载
var tempLink = document.createElement("a");
tempLink.style.display = "none";
tempLink.href = blobURL;
tempLink.setAttribute("download", filename);
if (typeof tempLink.download === "undefined") {
tempLink.setAttribute("target", "_blank");
}
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
window.URL.revokeObjectURL(blobURL);
}
},
//打印
pdfPrintAll() {
this.$refs.pdf.print();
},
//放大
scaleD() {
this.scale += 5;
this.$refs.pdf.$el.style.width = parseInt(this.scale) + "%";
},
//缩小
scaleX() {
// scale 是百分百展示 不建议缩放
if (this.scale == 100) {
return;
}
this.scale += -5;
console.log(parseInt(this.scale) + "%");
this.$refs.pdf.$el.style.width = parseInt(this.scale) + "%";
},
// 切换上一页
prePage() {
var p = this.pageNum;
p = p > 1 ? p - 1 : this.pageTotalNum;
this.pageNum = p;
},
// 切换下一页
nextPage() {
var p = this.pageNum;
p = p < this.pageTotalNum ? p + 1 : 1;
this.pageNum = p;
},
// pdf 有密码 则需要输入秘密
password(updatePassword, reason) {
updatePassword(prompt('password is "test"'));
console.log("...reason...");
console.log(reason);
console.log("...reason...");
},
// 页面加载成功 当前页数
pageLoaded(e) {
console.log("pageLoaded",e);
this.$emit("current", e);
this.curPageNum = e;
},
// 异常监听
pdfError(error) {
console.error('异常监听', error);
},
// getNumPages() {
// let loadingTask = pdf.createLoadingTask(this.pdfUrl);
// loadingTask.promise.then(pdf => {
// this.numPages = pdf.numPages;
// console.log('this.numPages', this.numPages)
// }).catch((err) => {
// console.error('pdf加载失败')
// })
// },
},
};
</script>
<style lang="scss" scoped>
.pdfView {
padding: 20px;
.show {
overflow: auto;
margin: auto;
max-width: 100%;
//height: 80vh;
max-height: 580px;
border: 2px solid #eee;
border-radius: 6px;
background-color: #eeeeee;
// 滚动条样式
&::-webkit-scrollbar {
width: 10px;
}
&::-webkit-scrollbar-thumb {
background-color: #999;
border-radius: 6px;
}
&::-webkit-scrollbar-track {
background-color: transparent;
border-radius: 6px;
}
}
.pdf_footer {
position: sticky;
bottom: 0;
left: 0;
right: 0;
padding: 10px 0;
background-color: rgba(255, 255, 255, 0.5);
.info {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
div {
width: 30%;
}
}
.operate {
margin: 10px 0 0;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
div {
// width: 80px;
text-align: center;
font-size: 15px;
}
.btn {
cursor: pointer;
margin: 5px 10px;
width: 120px;
border-radius: 10px;
padding: 5px;
color: #fff;
background-color: #3dcbbc;
}
}
}
}
</style>
这里给出了几种展示方式,有分页显示,有整页显示。按照项目需求可自行进行调整。
三、在页面你需要的地方引用
import PdfView from "@/components/PdfView";
import pdf from 'vue-pdf';
export default {
components:{pdf},
data(){
return{
pdf_img_url: null,//pdf文件路径
}
},
methods:{
downloadPDF(){
let url=this.pdf_img_url
let newTab = window.open(url, '_blank');
// 新窗口加载完后打印
newTab.onload = function() {
newTab.focus();
newTab.print();
};
},
printPdf() {
console.log('this???????',this.$refs.pdf);
this.$refs.pdf.pdfPrintAll()
},
}
}
<el-dialog
title="PDF文件预览"
:visible.sync="PdfViewVisible"
append-to-body
lock-scroll
width="50%"
:before-close="handleClosePdf"
>
<el-button @click="downloadPDF">下载</el-button>
<i class="el-icon-printer" @click="printPdf" style="cursor: pointer;float: right;font-size: 25px;"></i>//这是打印事件
<pdf-view :pdfUrl="pdf_img_url" ref="pdf" @load="onPDFLoaded"></pdf-view>
</el-dialog>
我这里放在了dialog中使用,可以根据自己实际需要的场景来进行使用。
预览是在当前页面打开的,不需要打开浏览器新窗口。
打印也是在当前页面打开了打印的窗口,但是需要注意有乱码的情况产生,这时需要更改插件的源文件。如果你的项目没有要求当前页面还是新窗口打开,那可以直接使用window.print(),可以参考下载的方法,调出浏览器自带的打印、下载事件(这个比较成熟,可以直接用)。
四、运行示例
注意:pdf_img_url我这里是请求后端接口拿到的,就不展示那部分代码了。
温馨提示:关闭dialog框时,记得清除pdf文件路径,避免打开下一个时还加载的是当一个文件。
好啦,这次的分享就进行到这了。博主也是第一次使用这个插件,在不断学习中,如果有朋友发现问题可进行评论交流学习。勿喷勿喷!!!