最近做到一个功能,PDF预览;这个功能看着蛮简单的,结果搞了两个下午,真是欲哭无泪。记录一下所查到的预览方法。
我在网上找了蛮多教程的,大致都是以下几个方法实现预览:
- 使用 iframe 标签
- 使用 embed 标签
- 安装 Vue 插件 vue-pdf
- 安装 Vue 插件 pdfh5
下面配合代码详细说我实现预览的过程吧!
iframe标签
<iframe :src="url" style="border: none;width: 100%;height: 100%;" frameborder="0" />
<script>
export default {
data() {
return {
show: false,
url: '', // pdf地址
}
},
methods: {
}
</script>
这个标签其实蛮方便的,毕竟上一页、下一页,跳转,下载都是齐全的,个人觉得如果是用在pc端就非常的舒适,一个标签解决所有,但是如果在移动端可能就有点小毛病;我这次需要在一个弹窗里预览PDF文件,在展示时样式就很丑(如下图),不过我没多挣扎就放弃了
embed 标签
<embed :src="url" type="application/pdf" width: 100% height: 100% >
<script>
export default {
data() {
return {
show: false,
url: '', // pdf地址
}
},
methods: {
}
</script>
这个方法有局限性,如果浏览器不支持PDF嵌入,那这个标签就什么也不展示。
Vue 插件 vue-pdf
npm install --save vue-pdf // 安装一下
<!--这是一次加载完,还可以分页展示,这里就不详细说了-->
<div class="toast">
<PDF v-for="i in pageNum" :key="i" ref="pdf" :src="url" :page="i" style="width: 100%" />
</div>
<script>
import PDF from 'vue-pdf' // 引入
import { CellGroup, Field, Popup, Toast } from 'vant'
export default {
components: {
PDF, [CellGroup.name]: CellGroup, [Field.name]: Field, [Popup.name]: Popup, [Toast.name]: Toast
},
data() {
return {
show: false, // 打开弹窗
url: '', // 预览地址
currentPage: 0, // 页码
pageNum: null
}
},
computed: {
},
created() {
},
methods: {
// 查看pdf
lookPdf(item) {
console.log('打开弹窗')
this.getNumPages()
this.show = true
},
getNumPages() {
this.url = 'https://xxx/xxxx/test.pdf'
const loadingTask = PDF.createLoadingTask(this.url)
loadingTask.promise
.then((pdf) => {
this.pageNum = pdf.numPages
})
.catch((err) => {
console.error('pdf 加载失败', err)
})
}
}
}
</script>
这个方法,我之前做PC端的时候,真的很丝滑;但这次做移动端就开始报错,用浏览器调试时,一到移动端模式就开始报错(如下图),在网上找的解决教程也没起作用,果断放弃。毕竟要多给别的方法机会嘛!
npm install pdfh5
npm install pdfh5 // 安装一下
<template>
<div class="m-pdf">
<div id="pdf-content" />
</div>
</template>
<script>
import Pdfh5 from 'pdfh5'
import 'pdfh5/css/pdfh5.css'
export default {
name: 'Pdfh5',
data() {
return {
pdfh5: null,
}
},
mounted() {
},
methods: {
initPdf(pdfUrl) {
console.log('子组件的地址', pdfUrl)
// pdfh5实例化时传两个参数:selector选择器,options配置项参数,会返回一个pdfh5实例对象,可以操作pdf,监听相关事件
this.pdfh5 = new Pdfh5('#pdf-content', {
pdfurl: pdfUrl
})
this.pdfh5.scrollEnable(true) // 允许pdf滚动
// 监听pdf准备开始渲染,可以拿到pdf总页数
this.pdfh5.on('ready', function() {
console.log('总页数:' + this.totalNum)
})
// 监听pdf加载完成事件
this.pdfh5.on('complete', (status, msg, time) => {
console.log('状态:' + status + ',信息:' + msg + ',耗时:' + time + '毫秒')
})
}
}
}
</script>
// 父组件
<template>
<button @click="showPdf">
<div v-if = "show">
<preview-pdf ref="previewPdfh5" style="height:450px;margin-bottom:12px;" />
</div>
</template>
<script>
import PreviewPdf from '../pdf.vue'
export default {
components: {
PreviewPdf
},
data() {
return {
show: false,
url: '', // pdf地址
}
},
methods: {
showPdf(){
this.show
this.url = 'https://xxx/xxxx/test.pdf' // pdf文件的地址
this.$refs.previewPdfh5.initPdf(this.url) // 父组件调用子组件的方法,动态渲染pdf
}
}
</script>
这个方法到这里也很丝滑,上述方法的问题都没有碰到;然而在调后端接口时,报错了。
真是欲哭无泪,我上网找教程,根本没有。接口传过来的PDF里有一些字段是动态变化的,就导致这个问题出现。在我不懈奋斗了几个小时之后,无意间看到了pdfh5的中文文档的一个参数例子(如图),问题就解决啦!
给代码加个参数
methods: {
initPdf(pdfUrl) {
console.log('子组件的地址', pdfUrl)
this.pdfh5 = new Pdfh5('#pdf-content', {
pdfurl: pdfUrl,
cMapUrl: 'https://unpkg.com/pdfjs-dist@2.0.943/cmaps/' // 改一下这个参数的默认地址
})
this.pdfh5.scrollEnable(true)
this.pdfh5.on('ready', function() {
console.log('总页数:' + this.totalNum)
})
this.pdfh5.on('complete', (status, msg, time) => {
console.log('状态:' + status + ',信息:' + msg + ',耗时:' + time + '毫秒')
})
}
}
这是我参考的文档地址:https://github.com/EncodingAESKey/pdfh5/blob/master/README.md
总结一下:磕磕碰碰也终于实现了功能。这几个方法都能实现功能;如果图方便就用iframe标签,图样式简洁且使用方法简单就用 vue-pdf 插件,图样式简洁且功能齐全就用 pdfh5 插件;至于embed 标签,我还没用过。不过我用 vue-pdf 插件遇到的问题,到现在也没解决好,不知道是不是移动端要添加什么配置,还是我代码环境不兼容;后面如果有好的解决方法,我会记得来更。