js取iframe 上級頁面_pdf.js實戰,含水印、電子簽章解決方案
阿新 • • 發佈:2021-01-13
技術標籤:js取iframe 上級頁面
專案涉及到移動端檢視電子合同的問題,前前後後試了三種方案,真是一步一個坑,三種方案各有各的優點,不水,直接上程式碼,按照自己的需求選擇。
一、pdf-vue
直接使用vue-pdf外掛,核心的程式碼是pdf.js,只不過就是自己封裝了一下,優點是方便快捷,缺點是無法載入電子簽章。
github地址
https://github.com/FranckFreiburger/vue-pd f#readme
1、npm install pdf-vue --save
2、template程式碼
class="pdf" v-show="fileType === 'pdf'">
class
="arrow">
// 上一頁
"changePdfPage(0)" class="turn" :class="{grey: currentPage==1}">Preview
{{currentPage}} / {{pageCount}}
// 下一頁
"changePdfPage(1)" class="turn" :class="{grey: currentPage==pageCount}">Next
// 自己引入就可以使用,這裡我的需求是做了分頁功能,如果不需要分頁功能,只要src就可以了
:src="src" // src需要展示的PDF地址
:page="currentPage" // 當前展示的PDF頁碼
@num-pages="pageCount=$event" // PDF檔案總頁碼
@page-loaded="currentPage=$event" // 一開始載入的頁面
@loaded="loadPdfHandler"> // 載入事件
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傳過來區分上一頁下一頁的值,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的一個元件,只不過沒有封裝,需要自己配置,優點是可配置,可實現特殊的需求,缺點是需要自己封裝,水印可載入,網上說可以載入電子簽章,我的載入不出來,所以還是沒采用。
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'
:pdfurl="pdfurl">
一開始專案使用的是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
:style="{height: Height}" style="width: 100%">
this.pdfUrl = '../pdf/web/viewer.html?file=' + this.pdfurl, +'PDF'
pdfUrl是iframe標籤的URL,pdfurl是需要檢視的PDF檔案的url
總結
只要能實現需求的程式碼就是好程式碼,我的專案是移動端檢視PDF檔案,因為檔案上有電子簽章,所以嘗試了好幾種方案,個人還是推薦第二種方案,如果沒有電子簽章的情況下。
各位哥哥姐姐點個關注吧