需求:移动端pdf预览,需要显示的内容包括中文,水印以及电子签章,后端接口返回base64的pdf文件数据
环境:vue2.x +mint-ui
接下来我们说两种预览pdf的方式,大家根据需求可以选择使用
方法一:vue-pdf
1.简洁的vue-pdf(在无需展示电子签章的情况下建议选择),使用方法非常简单;
// 安装vue-pdf
npm i vue-pdf --save
2.pdf展示页(pdf.vue)代码如下:
// 多页面pdf,有分页
<template><div> <div class="pdf" v-show="fileType === 'pdf'"> <p class="arrow"> <!-- // 上一页 --> <span @click="changePdfPage(0)" class="turn" :class="{grey: currentPage==1}">Preview</span> {{currentPage}} / {{pageCount}} <!-- // 下一页 --> <span @click="changePdfPage(1)" class="turn" :class="{grey: currentPage==pageCount}">Next</span> </p> <!-- // 自己引入就可以使用,这里我的需求是做了分页功能,如果不需要分页功能,只要src就可以了 --> <!-- src需要展示的PDF地址 --> <pdf :src="pdfSrc" :page="currentPage" @num-pages="pageCount=$event" @page-loaded="currentPage=$event" @loaded="loadPdfHandler"> </pdf> </div> <div class="footer-back" @click="goBack">返 回</div></div></template><script>import pdf from 'vue-pdf';// 显示中文,如果不引入CMapReaderFactory.js,中文有可能无法显示出来
import CMapReaderFactory from 'vue-pdf/src/CMapReaderFactory.js'; export default { components: { pdf }, data(){ return { pdfSrc:'', pdfUrl:'', currentPage: 0, // pdf文件页码 pageCount: 0, // pdf文件总页数 fileType: 'pdf', // 文件类型 } }, created(){ this.pdfSrc =pdf.createLoadingTask({ url: `data:application/pdf;base64,${this.$route.params.pdf}`, CMapReaderFactory }) ; }, methods: { changePdfPage (val) { const _this = this; if (val === 0 && _this.currentPage > 1) { _this.currentPage--; } if (val === 1 && _this.currentPage < _this.pageCount) { _this.currentPage++; } }, // pdf加载时 loadPdfHandler (e) { this.currentPage = 1; // 加载的时候先加载第一页 }, // 返回 goBack(){ this.$router.go(-1); } },};</script><style scoped> .footer-back { height: 0.9rem; width: 80%; margin: 0.3rem auto; background: #1492FF; line-height: 1rem; color: #fff; text-align: center; border-radius: 5px; font-size: 16px; }</style>
如果确定只是单页的pdf文件,可以直接使用如下代码:
<template><div> <pdf :src="pdfSrc"></pdf> <div class="footer-back" @click="goBack">返 回</div></div> </template> <script>import pdf from 'vue-pdf'
// 显示中文,如果不引入CMapReaderFactory.js,中文有可能无法显示出来
import CMapReaderFactory from 'vue-pdf/src/CMapReaderFactory.js';export default { components: { pdf }, data(){ return { pdfSrc:'' } }, created(){ this.pdfSrc =pdf.createLoadingTask({ url: `data:application/pdf;base64,${this.$route.params.pdf}`, CMapReaderFactory }) ; }, methods: { goBack(){ this.$router.go(-1); } },};</script><style scoped> .footer-back { height: 0.9rem; width: 80%; margin: 0.3rem auto; background: #1492FF; line-height: 1rem; color: #fff; text-align: center; border-radius: 5px; font-size: 16px; }</style>
这里注意一下,我的数据是放在params的pdf字段中的,所以可以使用this.$route.params.pdf,大家根据自己的数据来修改。
3.打开pdf页
// 跳转到pdf页,并将base64作为一个字段传给目标页面,这里注意配置好路由
// 我的base64数据存放字段dataBase64
this.$router.push( { name:'pdf预览', params: { pdf: dataBase64 } } )
// 我的路由
{ path: '/pdf', name: 'pdf预览', component: resolve => require(['../components/common/pdf.vue'], resolve), },
是不是很简单,但是vue-pdf在使用过程中有个目前我还没有找到解决办法的问题,就是电子签章问题,查询了很多地方,说只要注释掉node_modules/vue-pdf/pdfjsWrapper.js中的nnotationLayerElt.style.visibility = 'hidden';即可,但是本人亲测无效,如果有实现签章效果的朋友欢迎来纠正和指导,先谢谢了。
所以如果只是需要预览一个无需电子签章的pdf文件,那么使用vue-pdf非常方便。那么问题来了,我现在要显示电子签章怎么办,那就看下面的方法:pdf.js
方法二:pdf.js
1.下载pdf.js包,提供一下地址:
官方:mozilla.github.io/pdf.js/gett…
注意:需要修改源码,确保能够接收base64数据,并显示电子签章
2.将下载下来的包放置static目录下,作为静态文件存放,如果是cli3搭建的脚手架,放置在public目录下,这里我习惯将下载下来的包重命名为pdf,便于自己查看。
3.我网盘里面的包是修改过的,所以无需进一步修改,如果是官方下载的,需要做如下修改:
官方原代码:
需要新增的代码,用以处理base64数据:
<script type="text/javascript"> var DEFAULT_URL = ""; var pdfUrl = document.location.search.substring(1); if(null == pdfUrl || "" == pdfUrl){ var BASE64_MARKER = ';base64,';//声明文件流编码格式 var preFileId = ""; var pdfAsDataUri = localStorage.getItem("_pdf");//这里就是pdf文件的base64码,我是通过session传递base64的 var pdfAsArray = convertDataURIToBinary(pdfAsDataUri); DEFAULT_URL = pdfAsArray; //编码转换 function convertDataURIToBinary(dataURI) { //[RFC2045]中有规定:Base64一行不能超过76字符,超过则添加回车换行符。因此需要把base64字段中的换行符,回车符给去掉。 // var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length; var newUrl = dataURI.replace(/[\n\r]/g,''); var raw = window.atob(newUrl);//这个方法在ie内核下无法正常解析。 var rawLength = raw.length; //转换成pdf.js能直接解析的Uint8Array类型 var array = new Uint8Array(new ArrayBuffer(rawLength)); for (i = 0; i < rawLength; i++) { array[i] = raw.charCodeAt(i) & 0xff; } return array; } } </script>
其中我的base64是存放在缓存localStorage的_pdf字段中的,请根据自己的需求来处理;
结果:
接下来是处理电子签章的部分,找到pdf/build/pdf.worker.js的如下代码:
if (data.fieldType === 'Sig') { data.fieldValue = null; _this3.setFlags(_util.AnnotationFlag.HIDDEN); }
将其注释即可,亲测有效;
4.编写pdf.vue
<template><div> <iframe :src="pdfUrl" :style="{height: Height}" style="width: 100%"></iframe> <div class="footer-back" @click="goBack">返 回</div></div></template> <script> export default { data(){ return { pdfUrl:'', Height: '90vh' } }, created(){ this.pdfUrl = './static/pdf/web/viewer.html'; }, methods: { goBack(){ this.$router.go(-1); } },};</script><style scoped> .footer-back { height: 0.9rem; width: 80%; margin: 0.3rem auto; background: #1492FF; line-height: 1rem; color: #fff; text-align: center; border-radius: 5px; font-size: 16px; }</style>
注:“./static/pdf/web/viewer.html”该地址根据自己实际环境来做相应调整
5.跳转到pdf.vue页面,功能实现
// base64数据存放在dataBase64中
localStorage.setItem('_pdf',dataBase64); this.$router.push( { name:'pdf预览', params: { pdf: dataBase64 } } )
6.结果展示(因为内容涉及敏感信息,所以就打码了,但是所需要展示的功能点保留完整)
**总结:**使用vue-pdf好处就是简单,包小,如果应用在网络环境比较好的情况下,还可以使用CDN引入,这样可以减小打包后文件的大小。但是有个一直没有解决的问题是无法显示电子签章。使用pdf.js,增加了打包的容量,base64的数据需要做处理,viewer.html的路径也需要根据实际环境进行调整,但是有个非常明显的优势就是,功能强大,中文、水印、电子签章都能很好地显示出来。
感谢
最后,感谢您的阅读,如果以上内容存在疑问或者错误,欢迎留言提供宝贵意见和建议