开发过程中被要求实现pdf的预览,当时也正好没有文件系统,于是做了一个可以预览PDF和图片的组件,仅供参考
原理
1、通过获取文件后端下载接口返回的文件流,通过设置请求的responseType: 'blob'接收。
2、通过const blob = new Blob([res.data], { type: this.headerFileType })将请求返回的文件流转换为blob.
3、window.URL.createObjectURL(blob)生成预览的URL
4、通过<img alt="img" :src="blobPath || url" />元素预览
另:PDF通过ifram标签预览<iframe :src="url"></iframe>
废话不多说上代码
预览组件
<template>
<div class="content" v-loading="loading">
<div v-if="isPdf" class="pdf-name">{{ fileName || $route.query.fileName }}</div>
<iframe v-if="isPdf" :src="url" :style="iframeStyle" title="iframe"></iframe>
<div v-else style="text-align:center;">
<img alt="img" :src="blobPath || url" :style="imgStyle" @dblclick="imgDblclick" />
</div>
</div>
</template>
<script>
import TabContent from '@/components/wealth/layout/tab-content.vue'
import axios from 'axios'
export default {
components: { TabContent },
props: {
fileId: String, // 文件ID
fileName: String,
fileType: { // 预览的文件类型 pdf、jpg、png、jpeg
type: String,
default: 'pdf'
},
previewUrl: { // 默认产品中心 文件下载
type: String,
default: '/api/wp-product/v1/wp-product-file/downLoadFile/'
},
blobPath: { // blob文件流path
type: String,
default: ''
},
imgStyle: {
type: Object,
default: () => ({
width: '600px',
height: '600px'
})
},
iframeStyle: {
type: Object,
default: () => ({
width: '100%',
height: '100%'
})
}
},
data() {
return {
// 目前只支持get请求
url: '',
loading: false
}
},
watch: {
// 单独使用时候,传入fileId自动查询文件流生成为blobPath
fileId() {
this.getFileBuffer()
}
},
computed: {
isPdf() {
return this.fileType === 'pdf'
},
headerFileType() {
return this.isPdf ? 'application/pdf;charset-UTF-8;' : 'image/jpeg;charset-UTF-8;'
}
},
methods: {
getFileBuffer() {
this.loading = true
axios({
method: 'get',
url: `${window.location.origin}${this.previewUrl}${this.$route.query.fileId || this.fileId}`,
responseType: 'blob'
}).then(res => {
const blob = new Blob([res.data], {
type: this.headerFileType
})
this.url = window.URL.createObjectURL(blob)
}).finally(() => this.loading = false)
},
// 图片双击
imgDblclick() {
window.open(this.blobPath || this.url)
},
init() {
if (this.blobPath) return
this.getFileBuffer()
}
},
created() {
this.init()
}
}
</script>
<style lang="less" scoped>
.content {
width: 100%;
height: 100%;
.pdf-name {
position: absolute;
color: white;
top: 38px;
left: 85px;
width: 300px;
background-color: #313537;
height: 18px;
line-height: 18px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
</style>
在父组件中使用
// 接受生成的blobPath
<pdf-preview :blobPath="blobPath" fileType="png"></pdf-preview>
// 获取图片文件流
async getFileBuffer(file, index) {
await axios({
method: 'get',
url: `${window.location.origin}${this.previewUrl}${file.id}`,
responseType: 'blob'
}).then(res => {
/*
* 转换为blob流
*/
const blob = new Blob([res.data], {
type: 'image/jpeg;charset-UTF-8;'
})
/*
* window.URL.createObjectURL(blob)
* 通过blob流以及createObjectURL生成预览的blobPath
*/
this.$set(this.fileList[index], 'blobPath', window.URL.createObjectURL(blob))
})
}