基础介绍
DF文件在线预览的功能相信大家都是有遇到过的, 但在我平时的项目中, 公司提供了相应的插件, 但是在h5等其他项目中, 我们还是只能靠自己呀! 今天就大概说一下 vue-pdf 这个组件, 大部分的需求还是可以满足的。
vue-pdf实现pdf文件在线预览。
预览各方案对比
-
如果只想
简单在页面中嵌套 PDF,使用iframe / object / embed是最好的选择,它不需要你自己去编写翻页组件、不需要去调整样式,用户体验佳 -
如果对
样式没有定制化的需求,使用vueshowpdf也是非常不错,弹窗式的 UI 看起来会更加高大上。 -
如果对
权限控制、样式定制需求较高,使用vue-pdf是最好的选择,接口和属性较全,扩展能力强,自由度高。
填坑
使用vue-pdf打包生成***.worker.js,在使用cdn后跨域问题
方案一
步骤一:修改node_modules中的worker-loader/dist/workers/index.js
将publicPath 改为./
步骤二: 添加依赖patch-package,修改package.json
cnpm i patch-package --save-dev
在package.json中的scripts中添加 "postinstall": "patch-package"
步骤三:执行命令:npx patch-package worker-loader
执行完成后项目更目录会生成patches的目录,里面有一个补丁文件
文件中记录修改的内容步骤二与三的功能就是给node_modules打补丁。
步骤四:删除node_modules重新cnpm install,再打包就可以了。
代码提交git后其他人cnpm install后的依赖就是已经修改过的,我们公司使用的阿里云效的自动构建打包,云端构建部署,实测有效。项目运行是可以看到只有这个***.worker.js没有使用代理,功能正常!
方案二、将pdf包复制保存本地
src/components/vue-pdf/vuePdfNoSss.vue 文件
import resizeSensor from 'vue-resize-sensor'
export default function (pdfjsWrapper) {
var createLoadingTask = pdfjsWrapper.createLoadingTask
var PDFJSWrapper = pdfjsWrapper.PDFJSWrapper
return {
createLoadingTask: createLoadingTask,
render: function (h) {
return h(
'span', {
attrs: {
style: 'position: relative; display: block',
},
},
[
h('canvas', {
attrs: {
style: 'display: inline-block; width: 100%; height: 100%; vertical-align: top',
},
ref: 'canvas',
}),
h('span', {
style: 'display: inline-block; width: 100%; height: 100%',
class: 'annotationLayer',
ref: 'annotationLayer',
}),
h(resizeSensor, {
props: {
initial: true,
},
on: {
resize: this.resize,
},
}),
],
)
},
props: {
src: {
type: [String, Object, Uint8Array],
default: '',
},
page: {
type: Number,
default: 1,
},
rotate: {
type: Number,
},
},
watch: {
src: function () {
this.pdf.loadDocument(this.src)
},
page: function () {
this.pdf.loadPage(this.page, this.rotate)
},
rotate: function () {
this.pdf.renderPage(this.rotate)
},
},
methods: {
resize: function (size) {
// check if the element is attached to the dom tree || resizeSensor being destroyed
if (this.$el.parentNode === null || (size.width === 0 && size.height === 0)) return
// on IE10- canvas height must be set
this.$refs.canvas.style.height =
this.$refs.canvas.offsetWidth * (this.$refs.canvas.height / this.$refs.canvas.width) + 'px'
// update the page when the resolution is too poor
var resolutionScale = this.pdf.getResolutionScale()
if (resolutionScale < 0.85 || resolutionScale > 1.15) this.pdf.renderPage(this.rotate)
// this.$refs.annotationLayer.style.transform = 'scale('+resolutionScale+')';
},
print: function (dpi, pageList) {
this.pdf.printPage(dpi, pageList)
},
},
// doc: mounted hook is not called during server-side rendering.
mounted: function () {
this.pdf = new PDFJSWrapper(this.$refs.canvas, this.$refs.annotationLayer, this.$emit.bind(this))
this.$on('loaded', function () {
this.pdf.loadPage(this.page, this.rotate)
})
this.$on('page-size', function (width, height) {
this.$refs.canvas.style.height = this.$refs.canvas.offsetWidth * (height / width) + 'px'
})
this.pdf.loadDocument(this.src)
},
// doc: destroyed hook is not called during server-side rendering.
destroyed: function () {
this.pdf.destroy()
},
}
}
src/components/vue-pdf/vuePdfNoSss.vue 目录
< style src = "./annotationLayer.css" > < /style>
<script >
import componentFactory from './componentFactory.js'
let component = componentFactory({})
if (process.env.VUE_ENV !== 'server') {
var pdfjsWrapper = require('./pdfjsWrapper.js').default
var PDFJS = require('pdfjs-dist/es5/build/pdf.js')
const pdfjsWrapper = require('./pdfjsWrapper.js').default
const PDFJS = require('pdfjs-dist/es5/build/pdf.js')
if (typeof window !== 'undefined' && 'Worker' in window && navigator.appVersion.indexOf('MSIE 10') === -1) {
var PdfjsWorker = require('worker-loader?inline=true&fallback=false!pdfjs-dist/build/pdf.worker.js')
const PdfjsWorker = require('worker-loader?inline=true&fallback=false!pdfjs-dist/build/pdf.worker.js')
PDFJS.GlobalWorkerOptions.workerPort = new PdfjsWorker()
}
var component = componentFactory(pdfjsWrapper(PDFJS))
} else {
var component = componentFactory({})
component = componentFactory(pdfjsWrapper(PDFJS))
}
export default component
</script>
要注意这个地方改动
重新创建组件 src/pages/pdf-viewer/index.vue
<template>
<div>
<pdf v-for="i in numPages" :key="i" :src="pdfFile" :page="i" @page-loaded="pageLoaded"></pdf>
</div>
</template>
<script>
import pdf from '@/components/vue-pdf/src/vuePdfNoSss.vue'
import pdf from '@/components/vue-pdf/vuePdfNoSss.vue'
import { querystrs } from '@/utils/querystrs'
export default {
name: 'PDFViewer',
components: {
pdf,
},
data() {
return {
pdfUrl: decodeURIComponent(querystrs.pdf),
pdfFile: null,
numPages: undefined,
loadedRatio: 0,
}
},
created() {
this.pdfFile = pdf.createLoadingTask(this.pdfUrl)
},
mounted() {
this.getPdfFile()
},
methods: {
getPdfFile() {
Toast.loading()
this.pdfFile.promise
.then((pdf) => {
this.numPages = pdf.numPages
console.log(pdf)
})
.catch(() => {
Toast.hide()
window.location.replace(this.pdfUrl)
})
},
pageLoaded(currPage) {
if (currPage && currPage === this.numPages) {
Toast.hide()
}
return
},
},
}
</script>
<style lang="stylus" scoped></style>