需求及引言
最近在项目中,因为有一处需求,需要预览图片/PDF文件,Vue项目,索性采用了element-ui的dialog组件来展示文件。
图片预览很简单,直接在dialog组件放置一张图片,加入url即可。
但是PDF预览不太好处理,如果想要在dialog中放pdf,就需要用到vue-pdf(或者使用pdf.js,前者封装了后者,在vue中更加好用)
解决方案
采用vue-pdf来展示pdf
安装yarn add vue-pdf
例子
<template>
<!--
1. src: PDF路径
2. page:pdf当前页数
3. @num-pages:pdf的总页数
4. @page-loaded:加载时获取到页码
-->
// page: PDF的页数
<pdf
:src="PDF路径"
:page="pdfPage"
@num-pages="pdfPageCount = $event"
@page-loaded="pdfPage = $event"
></pdf>
<!-- 上下翻页 -->
<button @click="previousPage">上一页</button>
<button @click="nextPage">下一页</button>
</template>
<script>
import pdf from 'vue-pdf'
export default {
components: {
pdf
},
data() {
return {
pdfPage: 1,
pdfPageCount: 1,
}
},
methods: {
// 上一页
previousPage() {
let p = this.pdfPage;
p = p > 1 ? p - 1 : this.pdfPageCount;
this.pdfPage = p;
},
// 下一页
nextPage() {
let p = this.pdfPage;
p = p < this.pdfPageCount ? p + 1 : 1;
this.pdfPage = p;
}
}
}
</script>
<style></style>
此时,我们已经可以将一个PDF嵌入到页面中了。
存在的问题
1. 读取增加进度条
因为PDF会有过大的问题,所以为了提高用户体验,在加载PDF的时候会有一个进度条。由于本项目通过axios来进行HTTP请求,所以:
axios.create({
url: 'aabbcc',
method: 'GET',
responseType: 'blob',
// 在创建 axios 的实例时
// 这个时用来处理原生download的事件的
onDownloadProgress: progressEvent => { handleDownloadProgress(progressEvent) }
})
// 处理进度条问题
function handleDownloadProgress(e) {
// e.loaded 已经载入的
// e.total 所有
console.log(e.loaded / e.total)
}
可以通过onDownloadProgress来进行自定义处理进度条
2. 中文不展示
如果在读取PDF时,出现以下报错信息:
Warning: Error during font loading: The CMap “baseUrl” parameter must be specified, ensure that the “cMapUrl” and “cMapPacked” API parameters are provided.
在使用vue-pdf的组件中,
// 1. 引入
import CMapReaderFactory from 'vue-pdf/src/CMapReaderFactory.js';
// 2. 在使用时
this.pdfUrl = pdf.createLoadingTask({
url,
CMapReaderFactory
});
// 如果仍报错,就使用 CDN 加载 cMap
this.pdfUrl = pdf.createLoadingTask({
url,
cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.5.207/cmaps/',
cMapPacked: true
});
3. webpack 打包后出现[hash].worker.js
打包后在根路径会出现 worker.js 且,无法预览 pdf
解决方案:
找到node_modules/worker-loader/dist/index.js
const filename = _loaderUtils2.default.interpolateName(this, options.name || '[hash].worker.js', {
修改为 👇
const filename = _loaderUtils2.default.interpolateName(this, options.name || 'static/js/[hash].worker.js', {
这样打包后的worker.js文件就会存在于/static/js/了