vue3中如何使用pdfjs来展示pdf文档
在项目开发中碰到一个需求是在页面中展示pdf预览功能,本人的项目使用的是vue3,实现pdf预览使用的是pdf预览神器 pdfjs
以下,将详细介绍如何在项目中使用pdfjs,主要包括以下内容:
- 单页pdf加载
- 多页pdf加载
- pdf放大/缩小/大小重置
- pdf分页展示以及上下翻页
- pdf添加水印
- 动态添加pdf
- 从服务端获取pdf文件
参考资料: pdfjs源码及使用文档
1. 准备工作
1.1 pdfjs-dist 安装
百度搜索 npm pdfjs-dist,进入npm官方网站,即可查看pdfjs的安装方法:
安装命令:
npm i pdfjs-dist
2. 在vue3中使用pdfjs-dist查看pdf文档
2.1 基本页面代码
首先把基本的页面代码准备起来,具体代码如下:
<template>
<div class="pdf-container">
<canvas id="pdf-canvas"></canvas>
</div>
</template>
<script lang="ts">
import { Options, Vue } from 'vue-class-component'
import * as PdfJs from 'pdfjs-dist/legacy/build/pdf.js'
import Pdf from '@/assets/js.pdf'
@Options({})
export default class SinglePage extends Vue {
}
</script>
以上是使用的 vue3 的 class模式编写vue代码的方式,对于此种使用方式不清楚的,可以查看我的这篇文章:
超全的Vue中的Class Component使用总结
Vue中的Class Component使用指南
2.2 pdfjs工作原理简述
pdfjs展示pdf文档的原理,实际上是将pdf中的内容渲染到解析,然后渲染到 canvas 中进行展示,因此我们使用pdfjs渲染出来的pdf文件,实际上是一张张canvas图片。
2.3 pdf文件展示(单页
pdfjs的使用主要涉及到2个方法,分别是loadFile() 和 renderPage()
- loadFile()
主要用来加载pdf文件,其实现如下:
loadFile (url: string): void {
PdfJs.GlobalWorkerOptions.workerSrc = require('pdfjs-dist/build/pdf.worker.entry')
const loadingTask = PdfJs.getDocument(url)
loadingTask.promise.then((pdf) => {
this.pdfDoc = pdf
this.pdfPages = this.pdfDoc.numPages
this.$nextTick(() => {
this.renderPage(1)
})
})
}
以上代码因为使用了 ts ,有部分函数参数类型的设定,在使用过程中,如遇到ts的报错,可以直接把类型设置为 any.
需要注意: 以上部分的 workerSrc 赋值部分,需要特别注意,在pdfJs的使用示例中明确指出, workerSrc 的值要手动指定,如果没有指定此值,则会出现 workerSrc 未定义的bug, 另外,要注意,赋值时一定要赋值为 pdf.worker.entry (以entry结尾,表示入口)
- renderPage() 方法
主要用来将pdf文件的内容渲染到canvas上,其实现如下:
renderPage (num: any): void {
this.pdfDoc.getPage(num).then((page: any) => {
const canvas: any = document.getElementById('pdf-canvas')
const ctx: any = canvas.getContext('2d')
const dpr = window.devicePixelRatio || 1
const bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio ||
1
const ratio = dpr / bsr
const viewport = page.getViewport({ scale: this.pdfScale })
canvas.width = viewport.width * ratio
canvas.height = viewport.height * ratio
canvas.style.width = viewport.width + 'px'
canvas.style.height = viewport.height + 'px'
ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
const renderContext = {
canvasContext: ctx,
viewport: viewport
}
page.render(renderContext)
})
}
2.4 完整实现代码
<template>
<div class="pdf-container">
<canvas id="pdf-canvas"></canvas>
</div>
</template>
<script lang="ts">
import { Options, Vue } from 'vue-class-component'
import * as PdfJs from 'pdfjs-dist/legacy/build/pdf.js'
import Pdf from '@/assets/js.pdf'
@Options({})
export default class SinglePage extends Vue {
pdfDoc: any = ''
pdfPages = 0
pdfScale = 1.0
created () {
this.loadFile(Pdf)
}
loadFile (url: string): void {
PdfJs.GlobalWorkerOptions.workerSrc = require('pdfjs-dist/build/pdf.worker.entry')
const loadingTask = PdfJs.getDocument(url)
loadingTask.promise.then((pdf) => {
this.pdfDoc = pdf
this.pdfPages = this.pdfDoc.numPages
this.$nextTick(() => {
this.renderPage(1)
})
})
}
renderPage (num: any) {
this.pdfDoc.getPage(num).then((page: any) => {
const canvas: any = document.getElementById('pdf-canvas')
const ctx: any = canvas.getContext('2d')
const dpr = window.devicePixelRatio || 1
const bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio ||
1
const ratio = dpr / bsr
const viewport = page.getViewport({ scale: this.pdfScale })
canvas.width = viewport.width * ratio
canvas.height = viewport.height * ratio
canvas.style.width = viewport.width + 'px'
canvas.style.height = viewport.height + 'px'
ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
const renderContext = {
canvasContext: ctx,
viewport: viewport
}
page.render(renderContext)
})
}
}
</script>
2.5 效果
|