<template>
<div class="pdf-container">
<div v-if="loading" class="loading-state"><a-spin size="large" /></div>
<div v-else-if="error" class="loading-state">
加载失败,请关闭弹窗重新加载!
</div>
<div v-else class="pdf-viewer">
<pdf
v-for="i in numPages"
:key="`${pdfInstanceKey}-${i}`"
:src="pdfInstance"
:page="i"
class="pdf-page"
/>
</div>
</div>
</template>
<script>
import pdf from 'vue-pdf'
;
import {
debounce
}
from 'lodash-es'
;
export
default {
name: "PdfViewer"
,
components: {
pdf
}
,
props: {
currentPdfUrl: {
type: [String, Object]
, required: true
}
,
fileType: {
type: Number,
default: 1
}
}
,
data(
) {
return {
numPages: 0
,
pdfInstance:
null
,
pdfInstanceKey: 0
,
loading: false
,
error: false
,
activeLoadingTask:
null
,
currentBlobUrl:
null
}
;
}
,
watch: {
currentPdfUrl: {
immediate: true
,
deep: true
,
handler: debounce(
function(newVal
) {
if (newVal)
this.loadPdf(newVal)
;
}
, 300
)
}
}
,
methods: {
async loadPdf(source
) {
try {
this.loading = true
;
this.error = false
;
await
this.cleanupPreviousPdf(
)
;
const pdfSource =
this.fileType === 1
? {
url: source, withCredentials: false
}
:
this.createBlobUrl(source)
;
this.activeLoadingTask =
this.fileType === 1
? pdf.createLoadingTask({
url: source,
withCredentials: false
,
cMapUrl: '\'@/assets/cmaps/\''
,
cMapPacked: true
}
)
: pdf.createLoadingTask(
this.createBlobUrl(source)
)
;
this.pdfInstance =
this.activeLoadingTask;
const pdfDocument =
await
this.activeLoadingTask.promise;
this.numPages = pdfDocument.numPages;
this.pdfInstanceKey++
;
}
catch (err) {
console.error('PDF加载失败:'
, err)
;
this.handleLoadError(err)
;
}
finally {
this.loading = false
;
}
}
,
createBlobUrl(fileObj
) {
if (
this.currentBlobUrl) {
URL.revokeObjectURL(
this.currentBlobUrl)
;
}
this.currentBlobUrl = URL.createObjectURL(fileObj.originFileObj)
;
return
this.currentBlobUrl;
}
,
async cleanupPreviousPdf(
) {
if (
this.activeLoadingTask) {
try {
if (
this.activeLoadingTask._transport &&
this.activeLoadingTask._transport.destroy) {
this.activeLoadingTask._transport.destroy(
)
;
}
this.activeLoadingTask.destroy(
)
;
}
catch (e) {
console.warn('清理PDF worker时出错:'
, e)
;
}
this.activeLoadingTask =
null
;
}
this.pdfInstance =
null
;
this.numPages = 0
;
}
,
handleLoadError(error
) {
this.error = true
;
this.numPages = 0
;
if (error.name === 'PasswordException'
) {
console.warn('PDF需要密码'
)
;
}
else
if (error.name === 'InvalidPDFException'
) {
console.warn('无效的PDF文件'
)
;
}
}
,
retryLoading(
) {
this.loadPdf(
this.currentPdfUrl).catch((
)=>
{
}
)
;
}
}
,
beforeDestroy(
) {
this.cleanupPreviousPdf(
)
;
if (
this.currentBlobUrl) {
URL.revokeObjectURL(
this.currentBlobUrl)
;
}
}
}
;
</script>
<style scoped lang="less">
.pdf-container {
width: 100%;
//height: 100%;
overflow: auto;
background-color: #f0f0f0;
.pdf-viewer {
display: flex;
flex-direction: column;
align-items: center;
.pdf-page {
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15)
;
background-color: white;
width: 100%;
&:last-child {
margin-bottom: 0;
}
}
}
}
.loading-state{
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
</style>