vue框架中预览pdf(中文、水印、电子签章)

4,496 阅读3分钟

需求:移动端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数据,并显示电子签章

或者到我的网盘下载(已修改后的源码包--注释相关代码,以显示电子签章):地址已设置永久有效,无法获取可私信或者留言
链接:https://pan.baidu.com/s/1l302vEar2J4LCljHfGh7VQ 提取码:5pgj

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的路径也需要根据实际环境进行调整,但是有个非常明显的优势就是,功能强大,中文、水印、电子签章都能很好地显示出来。

感谢

最后,感谢您的阅读,如果以上内容存在疑问或者错误,欢迎留言提供宝贵意见和建议