項(xiàng)目涉及到移動(dòng)端查看電子合同的問題,前前后后試了三種方案,真是一步一個(gè)坑,三種方案各有各的優(yōu)點(diǎn),不水,直接上代碼,按照自己的需求選擇。
一、pdf-vue
直接使用vue-pdf插件,核心的代碼是pdf.js,只不過就是自己封裝了一下,優(yōu)點(diǎn)是方便快捷,缺點(diǎn)是無法加載電子簽章。
github地址: https://github.com/FranckFreiburger/vue-pdf#readme
1、npm install pdf-vue --save
2、template代碼
<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" // 當(dāng)前展示的PDF頁碼
@num-pages="pageCount=$event" // PDF文件總頁碼
@page-loaded="currentPage=$event" // 一開始加載的頁面
@loaded="loadPdfHandler"> // 加載事件
</pdf>
</div>
</template>
3、js代碼
import pdf from 'vue-pdf'
export default {
components: {pdf},
data () {
return {
currentPage: 0, // pdf文件頁碼
pageCount: 0, // pdf文件總頁數(shù)
fileType: 'pdf', // 文件類型
src: '', // pdf文件地址
}
},
created: {
// 有時(shí)PDF文件地址會(huì)出現(xiàn)跨域的情況,這里最好處理一下
this.src = pdf.createLoadingTask(this.src)
}
method: {
// 改變PDF頁碼,val傳過來區(qū)分上一頁下一頁的值,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加載時(shí)
loadPdfHandler (e) {
this.currentPage = 1 // 加載的時(shí)候先加載第一頁
}
}
}
使用非常方便,尤其是只需要翻頁,或者不需要翻頁的,強(qiáng)烈推薦。
二、pdf-dist
pdf-dist也是基于pdf.js的一個(gè)組件,只不過沒有封裝,需要自己配置,優(yōu)點(diǎn)是可配置,可實(shí)現(xiàn)特殊的需求,缺點(diǎn)是需要自己封裝,水印可加載,網(wǎng)上說可以加載電子簽章,我的加載不出來,所以還是沒采用。
1、npm install pdf-dist --save
2、封裝一個(gè)pdf.vue
<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',
// 接收父組件傳來的參數(shù)
props: ['pdfurl'],
components: { },
data () {
return {
pdfDoc: null, // pdfjs 生成的對(duì)象
pageNum: 1, //
pageRendering: false,
pageNumPending: null,
scale: 1, // 放大倍數(shù)
page_num: 0, // 當(dāng)前頁數(shù)
page_count: 0, // 總頁數(shù)
maxscale: 2, // 最大放大倍數(shù)
minscale: 0.8// 最小放大倍數(shù)
}
},
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 () { // 關(guān)閉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>
3、直接當(dāng)成組件,引用就可以了
import cdpdf from '../../../components/pdf.vue'
<cdpdf :pdfurl="pdfurl"></cdpdf>
一開始項(xiàng)目使用的是pdf-dist,因?yàn)楹髞黼娮雍炚嘛@示不出來:
Warning: Unimplemented widget field type "Sig", falling back to base field type.
從網(wǎng)上搜了很多方法,說是需要修改pdf.work.js的源碼,全局搜索AnnotationFlag.HIDDEN:
if(data.fieldType==='Sig') {
warn('unimplemented annotation type: Widget signature');
// 注釋下面這行代碼
this.setFlags(AnnotationFlag.HIDDEN);
}
可能是移動(dòng)端使用微信瀏覽器的原因,注釋掉代碼還是不好使,只能再想其他辦法了
三、pdf.js
最后用了最笨的辦法,直接從GitHub拉下來pdf.js的demo,用iframe標(biāo)簽包住demo里的HTML文件,直接套著用,完美解決電子簽章的問題:
1、從GitHub拉一下源碼,或者從這個(gè)地址直接下載
https://mozilla.github.io/pdf.js/getting_started/#download
下載下來以后放在public文件下(3.x腳手架)
2、iframe標(biāo)簽直接粗暴的設(shè)置src
<iframe :src="pdfUrl" :style="{height: Height}" style="width: 100%"></iframe>
this.pdfUrl = '../pdf/web/viewer.html?file=' + this.pdfurl, +'PDF'
pdfUrl是iframe標(biāo)簽的URL,pdfurl是需要查看的PDF文件的url
總結(jié)
只要能實(shí)現(xiàn)需求的代碼就是好代碼,我的項(xiàng)目是移動(dòng)端查看PDF文件,因?yàn)槲募嫌须娮雍炚?,所以嘗試了好幾種方案,個(gè)人還是推薦第二種方案,如果沒有電子簽章的情況下。
各位哥哥姐姐點(diǎn)個(gè)關(guān)注吧
