需求:有一个列表页,用户点击查看,弹层展示后台接口返回的pdf内容(不是文件、地址之类的,乱码的pdf铭文(二进制文件流))
1、pdf.js安装
npm install --save vue-pdf
2、正文代码
<template>
<div>
<el-table :data="dataList">
<el-table-column prop="fieldName" width="120" label="操作">
<template slot-scope="scope">
<span @click="look(scope.row)">查看</span>
</template>
</el-table-column>
</el-table>
<el-dialog title="预览" :visible.sync="dialogVisible" :before-close="closePdf">
<pdf v-for="i in numPages" :key="i" :src="pdfSrc" :page="i" />
</el-dialog>
</div>
<template>
<script>
import pdf from 'vue-pdf'
export default {
components: {
pdf
},
data() {
return {
dialogVisible: false,
numPages: 1,
pdfSrc:"",
close:false,
}
},
methods: {
// 查看预览
look(row) {
const that = this;
that.pdfSrc = "";
// 接口文件地址(接口入参拼出来的路径)
const url = `${Host}xxxxxx/xxxx/xxx?fileId=${row.fileId}&fileName=${row.fileName}.pdf`;
// 如果调用接口(接口的responseType一定要是blob,默认json,不然解析出来的pdf是空白的)后拿的返回的值(乱码的pdf铭文(二进制文件流))则需要转一下
// const url = window.URL.createObjectURL(new Blob([res]), { // res为接口返回值
// type: "application/msword"
// });
that.pdfSrc = pdf.createLoadingTask(url)
that.pdfSrc.promise.then(pdf => {
that.dialogVisible = true;
that.numPages = pdf.numPages
//保证pdf加载成功,否则不能关闭弹层
setTimeout(() => {
that.close = true;
}, 2000);
})
.catch(error => {
that.$message.error("无效的PDF文件!");
})
},
//此方法解决第一次查看pdf文字没有加载完成影响后续查看
closePdf(done){
if(this.close) {
this.numPages = 1;//必须重置,多次查看会出现头部内容缺失
this.close = false;
done();
} else {
this.$message.warning("PDF文件加载中");
}
}
}
}
</script>
遇到的问题:
1、多次查看后头部内容不显示。 设置numPages = 1;
2、上一条pdf查看没有加载完成,下一条pdf查看pdfSrc清空了还是无法正常加载。 延迟关闭弹层(这个方法有点暴力,希望能找到好的解决方法);
3、头部会有点多余内容溢出,内容没啥,就是感觉有类似border的东西。 头部其他内容设置样式盖住(具体css略)。
在后续项目中又实现了该功能,没有遇到以上问题,盲猜是因为pdf dialog标签上加了v-if,光设置visible.sync只会控制元素的显示隐藏,不会重新渲染。
总结:只要是dialog最好加上v-if,会避免很多问题。
拓展:
如果后端返回的是html格式,前端调用的接口responseType就不要用blob了,直接将返回结果放在v-html里面。例:
<div v-html="responseData"/>