首页 前端知识 vue-pdf使用及注意事项

vue-pdf使用及注意事项

2024-05-07 13:05:41 前端知识 前端哥 542 814 我要收藏

vue-pdf(vue预览pdf文件)的使用和注意事项

  • 需求简介
  • vue-pdf简介
  • 其它pdf预览方式
    • 一、HTML标签
    • 二、插件形式
  • vue-pdf的安装(有坑)
  • vue-pdf的使用
    • 一、安装file-loader(坑)
    • 二、本地测试pdf预览,两种方式(坑)
      • 1. pdf文件在public文件夹下
      • 2. 使用java后台返回文件流
    • 二、线上测试

需求简介

   近期公司有一个需求需要在移动端实现pdf文件预览,因为移动端是用vue开发的,所以最终选择使用vue-pdf插件进行开发。

vue-pdf简介

   vue-pdf是一个pdf预览的插件,主要在vue中使用,开发者是国外的(vue生态系统很大,也有国外的大佬参与了一些插件开发,主要是一些npm包),使用起来较为简单,就是坑有点多,如果公司要求没有那么严格,只是简单的预览功能,对样式也没有过多要求的话这个插件很不错。

官网链接:vue-pdf,https://hub.fgit.cf/FranckFreiburger/vue-pdf?tab=readme-ov-file
如果打不开,可以使用下面这个网址将链接复制进去加速访问
https://github.ur1.fun/

   尽量面向官网学习,这里有最为权威和全面的教程,就是英文页面有点烦人,适应一下,如果遇到问题可以百度看看解决方案。

简单总结一下官网列出的一些方法和属性

  • :src,用于绑定文件的URL
  • :page,用于展示第几页pdf,如果一个页面只渲染一页这个就会用到,翻页就是改变这个绑定的值
  • :rotate,旋转的角度,不常用
  • @password,当文档有密码时使用,不常用
  • @process,文档加载的进度,不常用
  • @loaded,当文档第一次加载时触发,不常用
  • @page-loaded,当页面加载时使用,当pdf翻页时会使用
  • @num-pages,pdf文件的总页数
  • @error,文件加载错误时触发
  • @lin-clicked,点击内部链接时触发,不常用
  • createLoadingTask,最常用的方法,加载pdf时使用
  • print,打印pdf的方法

其它pdf预览方式

一、HTML标签

  • iframe 标签
  • embed 标签
  • object 标签

   这三种都是使用HTML原生的标签,使用起来要么就是兼容性很差,要么就是不好理解或者不好开发,一般不建议使用。

二、插件形式

  • pdf.js
  • PDFObject

   大多数我们使用的就是插件,开发速度较快,其中最有名的就是pdf.js,现在很多pdf预览的第三方插件都是基于pdf.js封装的(包括vue-pdf),有兴趣的伙伴可以研究一下。

vue-pdf的安装(有坑)

安装命令:
npm install --save vue-pdf

   这是最基本的安装命令,但是这样安装极有可能会在最开始引入的时候import pdf form "vue-pdf就报错,如下:

MainTemplate.hooks.hotBootstrap has been removed (use your own RuntimeModule instead

   然后就是一顿找为什么会报这个错,网上大多数都是说版本的问题,需要降低版本,因为我们默认安装的话是最新版本(现在是4.3.0),这个版本兼容性不是很好,所以出现这个错误我们首先需要做的是:

  1. 使用命令卸载之前安装的vue-pdf

npm uninstall vue-pdf

  1. 指定版本安装(4.2.0)

npm install --save vue-pdf@4.2.0
npm install pdfjs-dist@2.5.207

   这里一定要卸载之前的版本,有时候就会有冲突,觉得不妥的伙伴可以在卸载后删除node_modules文件夹,重新加载一下再安装。
   一般情况下,执行上述命令就可以解决这个问题,但有时候在执行完后还是不行,这时候如果你执意要搜索为什么,答案普遍都是这个,有可能还有有一个说是脚手架版本太高,也就是@vue/cli版本是4.5以上,需要降一下版本,这时候可不要贸然去降低脚手架版本了,原因可能不是这个,注意了,vue-pdf的最新版本是2020年发布的,距离现在已经有3年了,我们都忽视了node版本,那时候的node版本可没有我们现在安装的那么高,所以就会出现不兼容的情况,(当时我使用的是node16,切换到14版本就可以了)这时候换个node版本,删除node_modules文件夹重新编译就可以解决引入报错的问题,如果不想卸载node可以参考我之前的nvm教程,快速切换node版本。

nvm使用

vue-pdf的使用

一、安装file-loader(坑)

npm install file-loader

   这里安装file-loader是做后面的本地测试用的,如果不安装则会导致本地测试的时候报错,无法识别pdf文件。Warning: Indexing all PDF objects

webpack配置

  1. 如果没有使用webpack链式编程,那在vue-config.js里面加一个
module.exports = defineConfig({
···
configureWebpack: {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|pdf)$/i,
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
},
},
],
}
}
})
复制
  1. 如果使用了webpack链式编程,也就是chainWebpack,配置如下
    在这里插入图片描述

二、本地测试pdf预览,两种方式(坑)

提前准备好一个pdf文件,实在找不到就新建一个docx文件,使用office导出为pdf文件。
在这里插入图片描述
   注意了:这里本地测试也分两种,如果是直接将pdf文件放在vue的工作环境下,必须放在public文件夹下面,不然使用require会报错;另外一种是后台返回文件流,之后会说怎么操作。

1. pdf文件在public文件夹下

<pdf
v-for="i in pageCount"
:src="pdfUrl"
:key="i + 'pdf'"
:page="i"
class="pdf-item"
></pdf>
复制

vue代码

/** pdf加载 */
async previewFile() {
try {
let loadingTask = pdf.createLoadingTask(this.pdfUrl);
loadingTask.promise.then(pdf => {
this.showPreviewFile = true;
this.pageCount = pdf.numPages;
}).catch((e) => {
console.log("pdf初始化错误", e);
Notify("文件初始化失败,请返回下载该文件查看")
})
} catch (e) {
this.$router.go(-1)
console.log("pdf加载出错了", e);
}
},
复制

js代码

pdfUrl是我的父组件传过来的(之后会附上完整代码),父组件中我的url是这样处理的

var testPdfUrl = require('@process/public/A票_8089139370.pdf')
复制

   这样写看起来没有什么毛病,使用require是为了得到pdf的路径,如果你是直接使用在标签上是没有什么问题的,但在实际操作中肯定是要把链接作为变量定义在data中,可是这样写报错了。
ype check failed for prop "pdfUrl"
   这里实际上是有一个坑的,如果你的require是使用在scipt标签中,解析出来的可不是一个string类型的连接哦,是一个对象,在对象中包含链接的属性,在控制台打印出来如下:
在这里插入图片描述
   其实最终file-loader会将pdf文件解析成一个物理路径返回,所以在真实测试的时候,需要将上面的代码稍微改造一下:

var testPdfUrl = require('@process/public/A票_8089139370.pdf').default
复制

   这样就可以实现基本的pdf预览,但一般的公司需求这样是满足不了的,大多数pdf都会有水印和签名的需求,现在的写法是展示不了水印和签名的,所以我们针对水印进行再次改造。

import CMapReaderFactory from 'vue-pdf/src/CMapReaderFactory.js' //引入水印依赖
复制

   在vue中引入水印依赖,之后改造pdf加载函数。

let loadingTask = pdf.createLoadingTask({
url: this.pdfUrl,
CMapReaderFactory
});
loadingTask.promise.then(pdf => {
this.pdfUrl = loadingTask
this.showPreviewFile = true;
this.pageCount = pdf.numPages;
}).catch((e) => {
console.log("pdf初始化错误", e);
Notify("文件初始化失败,请返回下载该文件查看")
})
复制

   在createLoading函数中增加了水印的配置,这样就可以正常加载水印的样式。而签名有点麻烦,经过不断查询资料最终选择了换包,将vue-pdf替换为vue-pdf-signature,这是一位大佬在npm发版的支持签名的包,经过测试没有出现问题,这里我们只需要在package.json中加入"vue-pdf-signature": "^4.2.7",直接npm i即可。最终改造的引入就是

import pdf from "vue-pdf-signature";
import CMapReaderFactory from "vue-pdf-signature/src/CMapReaderFactory"
复制

2. 使用java后台返回文件流

   这种实现方式就是前台发起请求,java后台返回一个文件流,之后前台处理成URL使用,当然一般这种使用的较少,如果你的pdf文件不大可以使用,有时候用来解决跨域问题比较好使,这个之后会说。

后台代码

@GetMapping("/testWordView")
@ResponseBody
public void testWordView(HttpServletResponse response, HttpServletRequest request) {
File file = new File("D:/personFile/word/test.docx");
if (file.exists()) {
OutputStream os = null;
try {
FileUtilService.setDownLoadName(request, response, "测试word文件.docx");
os = response.getOutputStream();
os.write(FileUtils.readFileToByteArray(file));
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
复制

前台代码:注意,要使用await关键字

var res = await testWordView()
this.pdfUrl = encodeURIComponent(this.getObjectURL(res));
// 将返回的流数据转换为url
getObjectURL (file) {
var binaryData = [];
binaryData.push(file);
let url = null;
if (window.createObjectURL !== undefined) { // basic
url = window.createObjectURL(new Blob(binaryData, {type: 'application/pdf,utf-8'}));
} else if (window.webkitURL !== undefined) { // webkit or chrome
try {
url = window.webkitURL.createObjectURL(new Blob(binaryData, {type: 'application/pdf,utf-8'}));
} catch (error) {
}
} else if (window.URL !== undefined) { // mozilla(firefox)
try {
url = window.URL.createObjectURL(new Blob(binaryData, {type: 'application/pdf,utf-8'}));
} catch (error) {
}
}
return url;
}
复制

二、线上测试

   刚才本地测试已经通过了,如果放到测试环境可能会出现一个问题,跨域!一般搜索资料会让我们去修改一下源码,这个方式不可取,放到线上就废了,有人可能说我给线上换包,那如果遇上升级node版本啥的,就不好使了,不能采用哦,而且据我根据网上的教程去找那段代码,在4.2.0版本是没有的。
在这里插入图片描述
   这种就是vue-pdf常见的跨域问题,出现的情况就是一般公司的文件是会单独拎出来一个服务器的,如果直接请求就会出现这种跨域问题,解决方式一般有三种

  1. 服务器直接配置支持跨域(不推荐,很不安全)
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS
Access-Control-Expose-Headers: Accept-Ranges, Content-Encoding, Content-Length, Content-Range
复制

使用的话就是ip加端口再加你的文件地址。
2. 使用文件流,就是上面测试使用的那种。
3. nginx代理(推荐使用)

location /files {
proxy_pass 目标服务器以及端口/;
}
复制

   这是公司常用的手段,一般肯定会有的,直接交给运维去配置,我们直接使用即可!

注意了:千万别再本地用测试环境的URL进行测试,除非你用文件流,因为无论你怎么配置都有跨域问题,我试验了好久,最后放到测试环境其实就OK了,pdf-js底层对这里进行了处理,这时候放到测试环境测试就可以了,不要像我一样在本地死磕啊

以上就是我对vue-pdf使用的一些总结,涵盖了大部分使用当中的坑,这里附上我封装的pdf组件。

<template>
<div class="process-fileView-pdf-container" ref="pdfView">
<div v-if="showPreviewFile" ref="pdf">
<pdf
v-for="i in pageCount"
:src="pdfUrl"
:key="i + 'pdf'"
:page="i"
class="pdf-item"
></pdf>
</div>
<div class="pdf-button-group" ref="fileViewBtnGroup">
<div class="div-item"><van-button class="btn-item back" type="info" @click="goBack">返回</van-button></div>
<div class="div-item"><van-button class="btn-item big" type="info" @click="scaleD">放大</van-button></div>
<div class="div-item"><van-button class="btn-item small" type="info" @click="scales">缩小</van-button></div>
</div>
</div>
</template>
<script>
import pdf from "vue-pdf-signature";
import CMapReaderFactory from "vue-pdf-signature/src/CMapReaderFactory"
import {Notify} from "vant";
export default {
name: "PdfView",
components: {
pdf
},
data() {
return {
// pdf总页数
pageCount: 1,
// 缩放
scale: 100,
timer: null,
showPreviewFile: false
}
},
mounted() {
this.previewFile()
},
props: {
pdfUrl: {
type: String,
default: ''
},
},
watch: {
pdfUrl: {
handler(newVal, oldVal) {
if (newVal) {
this.previewFile()
}
},
immediate: false
}
},
methods: {
/** pdf加载 */
async previewFile() {
try {
let loadingTask = pdf.createLoadingTask({
url: this.pdfUrl,
CMapReaderFactory
});
loadingTask.promise.then(pdf => {
this.pdfUrl = loadingTask
this.showPreviewFile = true;
this.pageCount = pdf.numPages;
}).catch((e) => {
console.log("pdf初始化错误", e);
Notify("文件初始化失败,请返回下载该文件查看")
})
} catch (e) {
this.$router.go(-1)
console.log("pdf加载出错了", e);
}
},
/** PDF放大 */
scaleD() {
if(this.scale>150) return false
this.scale += 10;
this.$refs.pdf.style.width = parseInt(this.scale) + "%";
},
/** PDF缩小 */
scales() {
if(this.scale<40) return false
this.scale -= 10;
this.$refs.pdf.style.width = parseInt(this.scale) + "%";
},
/** 返回 */
goBack() {
this.$router.go(-1)
},
}
}
</script>
<style lang="scss" scoped>
.process-fileView-pdf-container {
width: 100%;
height: 100%;
.pdf-item{
height: 100vh;
display: block !important;
}
.pdf-button-group {
position: fixed;
top: 10px;
right: 20px;
.btn-item {
width: 50px;
height: 50px;
border-radius: 100%;
}
.div-item {
margin-bottom: 8px;
}
::v-deep .van-button__text{
line-height: 20px;
}
}
}
</style>
复制
转载请注明出处或者链接地址:https://www.qianduange.cn//article/7368.html
标签
arcgis
评论
还可以输入200
共0条数据,当前/页
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!