項目涉及到移動端查看電子合同的問題厅贪,前前后后試了三種方案蠢护,真是一步一個坑,三種方案各有各的優(yōu)點养涮,不水葵硕,直接上代碼,按照自己的需求選擇贯吓。
一懈凹、pdf-vue
直接使用vue-pdf插件,核心的代碼是pdf.js悄谐,只不過就是自己封裝了一下介评,優(yōu)點是方便快捷,缺點是無法加載電子簽章爬舰。
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" // 當前展示的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文件總頁數
fileType: 'pdf', // 文件類型
src: '', // pdf文件地址
}
},
created: {
// 有時PDF文件地址會出現跨域的情況,這里最好處理一下
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加載時
loadPdfHandler (e) {
this.currentPage = 1 // 加載的時候先加載第一頁
}
}
}
使用非常方便棒掠,尤其是只需要翻頁孵构,或者不需要翻頁的,強烈推薦烟很。
二、pdf-dist
pdf-dist也是基于pdf.js的一個組件蜡镶,只不過沒有封裝雾袱,需要自己配置,優(yōu)點是可配置官还,可實現特殊的需求芹橡,缺點是需要自己封裝,水印可加載望伦,網上說可以加載電子簽章林说,我的加載不出來,所以還是沒采用屯伞。
1腿箩、npm install pdf-dist --save
2、封裝一個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',
// 接收父組件傳來的參數
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>
3劣摇、直接當成組件珠移,引用就可以了
import cdpdf from '../../../components/pdf.vue'
<cdpdf :pdfurl="pdfurl"></cdpdf>
一開始項目使用的是pdf-dist,因為后來電子簽章顯示不出來:
Warning: Unimplemented widget field type "Sig", falling back to base field type.
從網上搜了很多方法末融,說是需要修改pdf.work.js的源碼钧惧,全局搜索AnnotationFlag.HIDDEN:
if(data.fieldType==='Sig') {
warn('unimplemented annotation type: Widget signature');
// 注釋下面這行代碼
this.setFlags(AnnotationFlag.HIDDEN);
}
可能是移動端使用微信瀏覽器的原因,注釋掉代碼還是不好使勾习,只能再想其他辦法了
三浓瞪、pdf.js
最后用了最笨的辦法,直接從GitHub拉下來pdf.js的demo巧婶,用iframe標簽包住demo里的HTML文件乾颁,直接套著用,完美解決電子簽章的問題:
1粹舵、從GitHub拉一下源碼钮孵,或者從這個地址直接下載
https://mozilla.github.io/pdf.js/getting_started/#download
下載下來以后放在public文件下(3.x腳手架)
2、iframe標簽直接粗暴的設置src
<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文件,因為文件上有電子簽章诅需,所以嘗試了好幾種方案漾唉,個人還是推薦第二種方案荧库,如果沒有電子簽章的情況下。
各位哥哥姐姐點個關注吧