项目涉及到移动端查看电子合同的问题,前先后后试了三种方案,真是一步一个坑,三种方案各有各的优势,不水,直接上代码,按照本身的需求选择。html
直接使用vue-pdf插件,核心的代码是pdf.js,只不过就是本身封装了一下,优势是方便快捷,缺点是没法加载电子签章。vue
github地址: github.com/FranckFreib…git
<template>
<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就能够了
<pdf
:src="src" // src须要展现的PDF地址
:page="currentPage" // 当前展现的PDF页码
@num-pages="pageCount=$event" // PDF文件总页码
@page-loaded="currentPage=$event" // 一开始加载的页面
@loaded="loadPdfHandler"> // 加载事件
</pdf>
</div>
</template>
复制代码
import pdf from 'vue-pdf'
export default {
components: {pdf},
data () {
return {
currentPage: 0, // pdf文件页码
pageCount: 0, // pdf文件总页数
fileType: 'pdf', // 文件类型
    src: '', // pdf文件地址
}
},
  created: {
    // 有时PDF文件地址会出现跨域的状况,这里最好处理一下
    this.src = pdf.createLoadingTask(this.src)
  }
method: {
// 改变PDF页码,val传过来区分上一页下一页的值,0上一页,1下一页
changePdfPage (val) {
// console.log(val)
if (val === 0 && this.currentPage > 1) {
this.currentPage--
// console.log(this.currentPage)
}
if (val === 1 && this.currentPage < this.pageCount) {
this.currentPage++
// console.log(this.currentPage)
}
},
// pdf加载时
loadPdfHandler (e) {
this.currentPage = 1 // 加载的时候先加载第一页
}
}
}
复制代码
使用很是方便,尤为是只须要翻页,或者不须要翻页的,强烈推荐。github
pdf-dist也是基于pdf.js的一个组件,只不过没有封装,须要本身配置,优势是可配置,可实现特殊的需求,缺点是须要本身封装,水印可加载,网上说能够加载电子签章,个人加载不出来,因此仍是没采用。web
<template>
<div class="cpdf" id="cpdf">
<div class="center">
<canvas class="canvasstyle" id="the-canvas"></canvas>
<div class="contor">
<button @click="prev" style="margin-right: 10px">上一页</button>
<span>Page: <span v-text="page_num"></span> / <span v-text="page_count"></span></span>
<button @click="next" style="margin-left: 10px">下一页</button>
</div>
</div>
</div>
</template>
<script>
import PDFJS from 'pdfjs-dist'
export default {
name: 'c-pdf',
// 接收父组件传来的参数
props: ['pdfurl'],
components: { },
data () {
return {
pdfDoc: null, // pdfjs 生成的对象
pageNum: 1, //
pageRendering: false,
pageNumPending: null,
scale: 1, // 放大倍数
page_num: 0, // 当前页数
page_count: 0, // 总页数
maxscale: 2, // 最大放大倍数
minscale: 0.8// 最小放大倍数
}
},
methods: {
renderPage (num) { // 渲染pdf
let vm = this
this.pageRendering = true
let canvas = document.getElementById('the-canvas')
let ctx = canvas.getContext('2d')
let bsr =
ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio ||
1
let dpr = window.devicePixelRatio || 1
let ratio = dpr / bsr
// Using promise to fetch the page
this.pdfDoc.getPage(num).then(function (page) {
var viewport = page.getViewport(screen.availWidth / page.getViewport(1).width)
// alert(vm.canvas.height)
canvas.height = ratio * viewport.width
canvas.width = ratio * viewport.height
canvas.style.width = 1.5 * viewport.width + 'px'
canvas.style.height = 1 * viewport.height + 'px'
ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
// Render PDF page into canvas context
var renderContext = {
canvasContext: ctx,
viewport: viewport
}
var renderTask = page.render(renderContext)
// Wait for rendering to finish
renderTask.promise.then(function () {
vm.pageRendering = false
if (vm.pageNumPending !== null) {
// New page rendering is pending
vm.renderPage(vm.pageNumPending)
vm.pageNumPending = null
}
})
})
vm.page_num = vm.pageNum
},
addscale () { // 放大
if (this.scale >= this.maxscale) {
return
}
this.scale += 0.1
this.queueRenderPage(this.pageNum)
},
minus () { // 缩小
if (this.scale <= this.minscale) {
return
}
this.scale -= 0.1
this.queueRenderPage(this.pageNum)
},
prev () { // 上一页
let vm = this
if (vm.pageNum <= 1) {
return
}
vm.pageNum--
vm.queueRenderPage(vm.pageNum)
},
next () { // 下一页
let vm = this
if (vm.pageNum >= vm.page_count) {
return
}
vm.pageNum++
vm.queueRenderPage(vm.pageNum)
},
closepdf () { // 关闭PDF
this.$emit('closepdf')
},
queueRenderPage (num) {
if (this.pageRendering) {
this.pageNumPending = num
} else {
this.renderPage(num)
}
}
},
computed: {
ctx () {
let id = document.getElementById('the-canvas')
return id.getContext('2d')
}
},
mounted () {
let vm = this
PDFJS.getDocument(vm.pdfurl).then(function (pdfDoc_) { // 初始化pdf
vm.pdfDoc = pdfDoc_
vm.page_count = vm.pdfDoc.numPages
vm.renderPage(vm.pageNum)
})
}
}
</script>
<style lang="stylus" scoped>
.cpdf {
display: flex;
justify-content: center;
align-items: center;
.center {
text-align: center;
height: 100%;
overflow: hidden;
padding-top: 20px;
.contor {
position: fixed;
bottom: 30px;
left: 0;
width: 100%;
z-index: 99999;
font-size 30px
margin-top 20px
margin-bottom: 10px;
}
}
}
</style>
复制代码
import cdpdf from '../../../components/pdf.vue'
<cdpdf :pdfurl="pdfurl"></cdpdf>
复制代码
一开始项目使用的是pdf-dist,由于后来电子签章显示不出来:npm
Warning: Unimplemented widget field type "Sig", falling back to base field type.
复制代码
从网上搜了不少方法,说是须要修改pdf.work.js的源码,全局搜索AnnotationFlag.HIDDEN:canvas
if(data.fieldType==='Sig') {
warn('unimplemented annotation type: Widget signature');
// 注释下面这行代码
this.setFlags(AnnotationFlag.HIDDEN);
}
复制代码
多是移动端使用微信浏览器的缘由,注释掉代码仍是很差使,只能再想其余办法了跨域
最后用了最笨的办法,直接从GitHub拉下来pdf.js的demo,用iframe标签包住demo里的HTML文件,直接套着用,完美解决电子签章的问题:promise
mozilla.github.io/pdf.js/gett…浏览器
下载下来之后放在public文件下(3.x脚手架)
<iframe :src="pdfUrl" :style="{height: Height}" style="width: 100%"></iframe>
this.pdfUrl = '../pdf/web/viewer.html?file=' + this.pdfurl, +'PDF'
pdfUrl是iframe标签的URL,pdfurl是须要查看的PDF文件的url
复制代码
只要能实现需求的代码就是好代码,个人项目是移动端查看PDF文件,由于文件上有电子签章,因此尝试了好几种方案,我的仍是推荐第二种方案,若是没有电子签章的状况下。
公众号定时更新实战和基础博客,欢迎各位哥哥姐姐关注!