https://www.cnblogs.com/steamed-twisted-roll/p/9648255.html
最近做項目,遇到預覽PDF這個功能,在網上找了找,大多推薦的是pdf.js,不過在Vue中還是想偷懶直接npm組件,最后找到了一個還不錯的Vue-pdf 組件,GitHub地址:https://github.com/FranckFreiburger/vue-pdf#readme
<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 // 加載的時候先加載第一頁
}
}
}
</script>
實際效果

問題補充: 文件打印亂碼問題解決方法
之前有人問了關於PDF打印亂碼問題,我自己試了確實有這個問題,在官網找了一下,有人提交了代碼解決了這個問題,現在我把方法附上
原始的打印頁面,PDF格式亂碼,主要是因為PDF里使用了自定義字體,不能識別

需要修改vue-pdf安裝包的pdfjsWrapper.js文件

上面后綴為1的文件是原始的,紅線框起來的是我修改之后的文件
替換之后,打印就能正常顯示了,

博客園貌似不能上傳文件,代碼太多就不放上來了,如果有需要可以找我郵箱發你,或者到官網自己修改文件
git-hup地址:https://github.com/FranckFreiburger/vue-pdf/pull/130/commits/253f6186ff0676abf9277786087dda8d95dd8ea7,

上面提供的解決文件打印亂碼的問題,實現起來比較麻煩,而且現在vue-pdf的版本已經更新了,用這個方法可能還會出現空白頁的問題.如果對項目沒什么要求,可用用iframe來預覽打印,效果會更好些,這里把方法放上來,有需要的可以試試
這里的例子是把PDF文件放在elment的彈框中,當然你可以根據你自己的適用場景來決定
html:
<el-dialog
:close-on-click-modal="false"
:visible.sync="dialogVisible"
:fullscreen="true"
title="文件預覽">
<div class="agreement_picture">
<div class="pdf">
<!-- <pdf // 之前的用PDF插件的方法
v-for="i in pdf.numPages"
:key="i"
:page="i"
:src="src">
</pdf> -->
// 使用iframe方法
<iframe :src="src" frameborder="0" style="width: 100%; height: 100%"></iframe>
</div>
</div>
<span slot="footer" class="dialog-footer">
<div class="tip-left transfer">
<el-button type="info" @click="dialogVisible=false">不同意</el-button>
<el-button type="danger" @click="agreeSignFun">同意</el-button>
</div>
</span>
</el-dialog>
js:
data () {
return {
src: '/static/file/中國互聯網整體網民發展狀況——《第31次中國互聯網發展狀況調查報告(上)》.pdf', //pdf地址,這里我用的是我本地的文件,你也可以使用后台的文件
dialogVisible: true
}
}
效果展示:

打印效果:

補充內容:
朋友們,關於跨域問題,我這里說明一下,如果你是在本地localhost環境請求后台接口返回的文件地址,一般都會跨域,報錯如下

這個文件地址我在瀏覽器可以直接打開預覽

遇到這種問題,是因為你本地的localhost和你后台返回的域名不一致,可以先用一個本地靜態文件調試效果,在線上環境即通過打包部署的環境(域名和返回的PDF域名一致的環境)再看效果.
另外補充一下打印的問題,通過vue-pdf自帶的打印功能,打印出來的效果一般是這樣

這個作者在git上也說了,現在vue-pdf的打印功能還在試驗階段,沒有完善,所以寄希望於這個方法實現打印還需一段時日,上面的內容里我用了<iframe>標簽來預覽打印,但是現在iframe已經不怎么使用了,有些項目還不允許用,這里我再補充兩種打印方法
1. 先把PDF內容轉成圖片后再打印
<el-dialog
title="文件預覽"
:visible.sync="dialogVisible"
width="50%"
>
<div ref="printContent">
<!-- 加載全部頁面的PDF是循環生成,不能指定ref,不能調用print打印方法 -->
<Pdf
v-for="i in numPages"
:key="i"
:src="src"
:page="i"
/>
<!-- 寫一個隱藏的PDF,用來調用打印 -->
<Pdf
v-show="false"
ref="printPdf"
:src="src"
/>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="print">vue-pdf自帶打印</el-button>
<el-button type="primary" @click="toImg">轉圖片打印</el-button>
</span>
</el-dialog>
<script>
import Pdf from 'vue-pdf'
import html2canvas from 'html2canvas'
import printJS from 'print-js'
export default {
components: {
Pdf
},
data() {
return {
fileList: [
{
id: 1,
fileName: '增進函',
fileUrl: 'http://172.16.79.33:8888/group1/.........../rBBPIV7whg2AQNCmAAoc6DKtkwE841.pdf'
},
{
id: 2,
fileName: '應收賬款',
fileUrl: `${window.location.origin}/test1.pdf`
}
],
numPages: undefined,
dialogVisible: false,
src: '',
printName: '轉圖片打印'
}
},
created() {
},
methods: {
// 預覽
preview(item) {
this.src = Pdf.createLoadingTask(item.fileUrl)
this.src.promise.then(pdf => {
this.numPages = pdf.numPages
})
this.dialogVisible = true
this.printName = item.fileName
},
// 轉圖片打印
toImg() {
html2canvas(this.$refs.printContent, {
backgroundColor: null,
useCORS: true,
windowHeight: document.body.scrollHeight
}).then((canvas) => {
const url = canvas.toDataURL()
printJS({
printable: url,
type: 'image',
documentTitle: this.printName
})
// console.log(url)
})
},
// pdf自帶打印
print() {
this.$refs.printPdf.print()
}
}
}
打印效果

2.跳轉頁面打印,這種和iframe的差不多,新建一個頁面,調用window.print()打印頁面,效果如下

如果以上都不能解決你的問題,我覺得你可以使用window.open()直接新頁面打開預覽,使用瀏覽器自帶的打印預覽功能.
路徑問題報錯
如果引入文件后,(一般是引入靜態文件),PDF沒有展示出來,並且控制台返回如下

這種情況是你的文件路徑不對,現在使用的vue版本大部分都是新版的,文件夾里去掉了static文件,新增的是public文件,
這個問題可以看我的另一篇關於文件路徑引用的博客https://www.cnblogs.com/steamed-twisted-roll/p/13278940.html
現在一般項目為了安全性,不會直接返回文件地址,會返回文件流的格式,對於文件流格式文件可以轉化成blob文件,如果有需要可以看下我另一篇博客:文件流數據如何轉blob文件 https://www.cnblogs.com/steamed-twisted-roll/p/11821148.html
// 瀏覽器中不預覽pdf文件直接下載

