项目中需要查看PDF文件,依次使用了vue-pdf、pdf-dist,发现最好用的是下面链接的解决方案,基于pdf-dist的一种方案。
1、安装pdf-dist
npm install pdf-dist --save
2、新建一个pdfPreview.vue文件
<template>
<div class="container">
<div
v-for="page in pages"
:key="page"
ref="pageContainer"
:style="{
borderBottom: '1px solid #DFDFDF',
height: pageHeight + 'px'
}">
<canvas v-if="renderList.includes(page)"></canvas>
</div>
</div>
</template>
<script>
import pdfJS from 'pdfjs-dist'
export default {
props: {
url: {
type: String,
required: true
},
manualRender: {
type: Boolean,
default: false
},
renderPages: { // 前后各预渲染多少页
type: Number,
default: 5
},
showPageLine: {
type: Boolean,
default: true
}
},
data () {
return {
pdfDoc: null,
pages: 0,
currentPage: 0,
pageHeight: 0,
renderList: [], // 渲染的页码数组
timerIndex: 0
}
},
watch: {
url () {
this.getPDFFile()
}
},
created () {
this.getPDFFile()
if (!this.manualRender) {
document.addEventListener('scroll', this.documentScroll)
}
},
beforeDestroy () {
document.removeEventListener('scroll', this.documentScroll)
this.timerIndex && clearTimeout(this.timerIndex)
},
methods: {
getPDFFile () {
if (!this.url) return
pdfJS.getDocument(this.url).then(pdf => {
this.pdfDoc = pdf
this.pages = this.pdfDoc.numPages
this.$nextTick(() => {
this.pages && this.scrollToPage(1)
})
})
},
scrollToPage (pageNo) {
if (this.currentPage === pageNo) return
this.currentPage = pageNo
let list = []
for (let page = pageNo - this.renderPages; page <= pageNo + this.renderPages; page++) {
list.push(page)
}
for (let idx = list.length; idx >= 0; idx--) {
if (list[idx] > this.pages || list[idx] < 1) list.splice(idx, 1)
}
this.$nextTick(() => {
this.renderList = list
this.renderList.forEach(page => {
this.renderPage(page)
})
})
},
renderPage (pageNo) {
this.pdfDoc.getPage(pageNo).then(page => {
let containerNode = this.$refs.pageContainer[pageNo - 1]
if (!containerNode) return
let canvas = containerNode.querySelector('canvas')
if (!canvas || canvas.__rendered) return
let ctx = canvas.getContext('2d')
let dpr = window.devicePixelRatio || 1
let bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1
let ratio = dpr / bsr
let viewport = page.getViewport(screen.availWidth / page.getViewport(.5).width)
canvas.width = viewport.width * ratio
canvas.height = viewport.height * ratio
canvas.style.width = viewport.width + 'px'
canvas.style.height = viewport.height + 'px'
this.pageHeight = viewport.height
ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
let renderCtx = {
canvasContext: ctx,
viewport
}
page.render(renderCtx)
canvas.__rendered = true
})
},
documentScroll () {
this.checkRender()
},
checkRender () {
this.timerIndex && clearTimeout(this.timerIndex)
this.timerIndex = setTimeout(this.renderCurrent, 100)
},
renderCurrent () {
this.$nextTick(() => {
if (this.pages <= 0) return
if (!this.pageHeight) return
if (!this.$refs.pageContainer[0]) return
let rect = this.$refs.pageContainer[0].getBoundingClientRect()
if (rect.top >= 0) {
this.scrollToPage(1)
} else {
let page = Math.floor(-rect.top / this.pageHeight) + 1
if (page > this.pages) page = this.pages
this.scrollToPage(page)
}
})
}
}
}
</script>
3、项目中直接引用组件,搞定
import pdfPreview from './components/PdfPreview.vue'
<pdf-preview :url="url"></pdf-preview>
个人的微信公众号:小Jerry有话说,平时会发一些技术文章和读书笔记,欢迎交流。