vue-pdf,实现pdf文件在线预览,放大缩小,下一页上一页,打印,禁止页面鼠标右击,禁用F12
一、安装
npm install --save vue-pdf
二、pdf标签使用
1.基础用法(显示一页)
<template> <div> <pdf ref="pdf" :src="url"></pdf> </div> </template>
<script> import pdf from 'vue-pdf' export default { components:{pdf}, data(){ return { url:"http://文件路径地址", } } </script>
2.显示多页
这时候我们可以通过滑动预览pdf的内容, 但是这种方式是一下子把pdf的内容都加载出来, 页数一多, 浏览器直接卡在加载的状态, 体验感太差,所以我们可以考虑按页加载
<template> <div> <pdf ref="pdf" v-for="i in numPages" :key="i" :src="url" :page="i" ></pdf> </div> </template>
<script> import pdf from 'vue-pdf' export default { components:{ pdf }, data(){ return { url:"http://文件路径地址", numPages: null, // pdf 总页数 } }, mounted() { this.getNumPages() }, methods: { // 计算pdf页码总数 getNumPages() { let loadingTask = pdf.createLoadingTask(this.url) loadingTask.promise.then(pdf => { this.numPages = pdf.numPages }).catch(err => { console.error('pdf 加载失败', err); }) }, } </script>
3.分页预览
<template> <div> <el-button-group> <el-button type="primary" icon="el-icon-arrow-left" size="mini" @click="prePage">上一页</el-button> <el-button type="primary" size="mini" @click="nextPage">下一页<i class="el-icon-arrow-right el-icon--right"></i></el-button> </el-button-group> <div style="marginTop: 10px; color: #409EFF">{{ pageNum }} / {{ pageTotalNum }}</div> <pdf :page="pageNum" :src="url" @progress="loadedRatio = $event" @num-pages="pageTotalNum=$event" ></pdf> </div> </template>
<script> import pdf from 'vue-pdf' export default { name: 'Pdf', components: { pdf, }, data() { return { url: 'http://文件路径地址', pageNum: 1,//文件页码 pageTotalNum: 1, //总页数 loadedRatio: 0, //当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了 } }, created: { // 有时候pdf文件地址会出现跨域的情况,这里最好处理一下 this.src = pdf.createLoadingTask(this.src) }, methods: { // 上一页 prePage() { let page = this.pageNum page = page > 1 ? page - 1 : this.pageTotalNum this.pageNum = page }, // 下一页 nextPage() { let page = this.pageNum page = page < this.pageTotalNum ? page + 1 : 1 this.pageNum = page } } } </script>
参数介绍:
page
: 当前显示的页数,比如第一页page=1rotate
: 旋转角度,比如0就是不旋转,+90,-90 就是水平旋转。progress
:当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了。page-loaded
:页面加载成功的回调函数,不咋能用到。num-pages
:总页数error
:加载错误的回调link-clicked
:单机pdf内的链接会触发。
其他:
- print 这个是打印函数。 注意:谷歌浏览器会出现乱码,这个和字体有关系。
三、完整项目示例
<template> <div class="app-container"> <!-- 文件预览 --> <el-dialog :close-on-click-modal="false" title="文件预览" :visible.sync="dialogVisible" append-to-body fullscreen class="pdf_dialog" @close="closePDF" > <div class="pdf_fixed_bottom"> <el-input-number class="mr10" controls-position="right" v-model="jumpNum" :min="1" :max="pdfpageTotalNum" :step="1" step-strictly label="请输入页码" size="mini" > </el-input-number> <el-button type="primary" @click="jumpPage" size="mini" class="pdf-btn-size" > 跳转 </el-button>
<el-button type="primary" @click="preClockwise" size="mini"> <img src="@/assets/image/7.png" /> //右旋转 </el-button> <el-button type="primary" @click="preAntieClockwise" size="mini"> <img src="@/assets/image/8.png" /> //左旋转 </el-button> <el-button type="primary" @click="prePage" size="mini"> <img src="@/assets/image/2.png" /> //上一页 </el-button> <el-button type="primary" @click="nextPage" size="mini"> <img src="@/assets/image/3.png" /> //下一页 </el-button> <el-button type="primary" :class="{ select: idx == 0 }" @touchstart="idx = 0" @touchend="idx = -1" @click="scaleD" size="mini" > <img src="@/assets/image/5.png" /> //放大 </el-button> <el-button type="primary" :class="{ select: idx == 1 }" @touchstart="idx = 1" @touchend="idx = -1" @click="scaleX" size="mini" > <img src="@/assets/image/6.png" /> //缩小 </el-button> <el-button type="primary" @click="print" size="mini" class="pdf-btn-size" > <img src="@/assets/image/9.png" /> //打印 </el-button> </div> <div class="page pdf_fixed_top"> 当前第{{ pdfpageNum }}页/共{{ pdfpageTotalNum }}页 </div> <div class="pdf_transform"> <pdf ref="pdf" :src="pdfurl" :page="pdfpageNum" :rotate="pdfpageRotate" @progress="pdfloadedRatio = $event" @page-loaded="pageLoaded($event)" @num-pages="pdfpageTotalNum = $event" @error="pdfError($event)" @link-clicked="pdfpage = $event" v-loading="dialogloading" > </pdf> </div> </el-dialog> </div> </template>
<script> import { getToken } from "@/utils/auth"; import { downloadNew } from "@/utils/ruoyi"; import { messagePrompt } from "@/utils/message"; //提示语集合 import { parameterPrompt } from "@/utils/parameter"; //固定参数集合 import pdf from "@/vue-pdf"; import Watermark from "@/utils/watermark"; export default { name: "test", components: { pdf, }, data() { return { // pdf预览 dialogloading: false, dialogVisible: false, pdfurl: " ", pdfpageNum: 1, pdfpageTotalNum: 1, pdfpageRotate: 0, jumpNum: 0, // 加载进度 pdfloadedRatio: 0, pdfcurPageNum: 0, scale: 1, //放大系数 idx: -1, }; }, created() { this.stopF5Refresh(); }, methods: { /** PDF预览 */ // 预览pdf弹窗 openDialogVisible(url) { var date = new Date(); var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); if (month < 10) { month = "0" + month; } if (day < 10) { day = "0" + day; } var nowDate = year + "-" + month + "-" + day; var name = "aaa"; this.pdfurl = url; Watermark.set(name + nowDate); //水印格式:登录人+年月日 this.dialogloading = true; this.dialogVisible = true; }, // 关闭pdf closePDF() { Watermark.set(""); this.dialogVisible = false; this.pdfpageNum = 1; this.pdfloadedRatio = 0; this.pdfpageRotate = 0; this.scale = 1; this.idx = -1; this.pdfurl = null; this.$refs.pdf.$el.style.transform = "scale(" + this.scale + "," + this.scale + ")"; this.$refs.pdf.$el.style.transformOrigin = "0% 0%"; }, //放大 scaleD() { this.scale += 0.1; this.$refs.pdf.$el.style.transform = "scale(" + this.scale + "," + this.scale + ")"; this.$refs.pdf.$el.style.transformOrigin = "0% 0%"; }, //缩小 scaleX() { this.scale += -0.1; this.$refs.pdf.$el.style.transform = "scale(" + this.scale + "," + this.scale + ")"; this.$refs.pdf.$el.style.transformOrigin = "0% 0%"; }, //顺时针 preClockwise() { this.pdfpageRotate = this.pdfpageRotate + 90; }, //逆时针 preAntieClockwise() { this.pdfpageRotate = this.pdfpageRotate - 90; }, // 上一页函数, prePage() { var page = this.pdfpageNum; page = page > 1 ? page - 1 : this.pdfpageTotalNum; this.pdfpageNum = page; }, // 下一页函数 nextPage() { var page = this.pdfpageNum; page = page < this.pdfpageTotalNum ? page + 1 : 1; this.pdfpageNum = page; }, //跳转 jumpPage(e) { this.pdfpageNum = this.jumpNum; }, //打印 print() { this.$refs.pdf.print(); }, // 页面加载回调函数,其中e为当前页数 pageLoaded(e) { this.pdfcurPageNum = e; if (this.pdfloadedRatio === 1) { this.$nextTick(() => { setTimeout(() => { this.dialogloading = false; }, 500); }); } }, // 其他的一些回调函数。 pdfError(error) { console.error(error); }, /* 禁止一系列查看的快捷键 */ stopF5Refresh() { document.onkeydown = function (e) { var evt = window.event || e; var code = evt.keyCode || evt.which; //屏蔽F1---F12 if (code > 111 && code < 124) { if (evt.preventDefault) { evt.preventDefault(); } else { evt.keyCode = 0; evt.returnValue = false; } } //禁止ctrl+s if (e.ctrlKey && e.keyCode == 83) { return false; } }; //禁止鼠标右键菜单 document.oncontextmenu = function (e) { return false; }; //阻止后退的所有动作,包括 键盘、鼠标手势等产生的后退动作。 history.pushState(null, null, window.location.href); window.addEventListener("popstate", function () { history.pushState(null, null, window.location.href); }); }, }, }; </script> <style lang="scss"> .pdf_dialog { .el-dialog__header { position: fixed !important; width: 100% !important; z-index: 999 !important; padding-bottom: 14px !important; background: #fff !important; } .el-dialog.is-fullscreen { background: #525659 !important; } .el-dialog__body { margin-top: 60px !important; height: 100% !important; padding: 20px !important; } } canvas { margin-bottom: 40px !important; } </style>
四、更多内容参考
Vue PDF文件预览vue-pdf
npm vue-pdf
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通