分享一个将图片和PDF二进制文件流转化为可以查看的地址
需求
继上一次在表格中需要将树类型扁平化为数组之后,产品说为了更满足客户的适用性,需要将文件名称后缀为jpg、jpeg、png的文件点击能够查看图片,后缀为pdf的文件能够查看pdf(之前的需求是点击文件名称下载文件)。其实这个需求应该是很简单的,只要后端返回src能够查看的地址就可以;但是期望总是相反的,后端大哥不返,那么就只能自己来进行转换。
解决步骤
1、先为每一个列表数据做一个分类-----picture、pdf、other。
// 为资料分类--图片和pdf可以预览
this.dataList.map(item => {
let arr = []
arr = item.fileName.split('.') // 以.来进行分割
let str = arr[arr.length - 1].toLocaleLowerCase() // 可能是大写的后缀
switch (str) {
case 'png':
item.type = 'picture'
break;
case 'jpg':
item.type = 'picture'
break;
case 'jpeg':
item.type = 'picture'
break;
case 'pdf':
item.type = 'pdf'
break;
default:
item.type = 'other'
break;
}
})
以fileName来做区分,因为考虑到文件名称可能有多个".“符号,所以就以”."来进行分割,取数组最后一个数据来进行区分。又因为可能文件后缀有大小写的情况,所以就统一处理为小写然后来进行判断。将数据进行处理后的结构为下图:多了一个type属性来进行判断
<span v-if="row.type == 'other'" @click="downFile(row)" class="filename">{{row.fileName ? row.fileName : '--'}}</span>
<span v-else-if="row.type == 'picture'" @click="pictureView(row)" class="filename">{{row.fileName ? row.fileName : '--'}}</span>
<span v-else @click="PDFView(row)" class="filename">{{row.fileName ? row.fileName : '--'}}</span>
HTML的结构就可以根据type来进行区分渲染,这个地方其实可以做一个优化,写一行代码,用同一个方法,在方法里面在进行type判断即可。后面我也会进行优化,当然这不是重点啦。
2、每一行数据有type分类以后,就可以根据类比进行不同的功能展示了。
首先是图片的展示-----为了单独使用element-ui的图片预览功能,所以需要将预览功能的组件单独引入。
<!-- 查看图片 -->
<el-image-viewer v-if="dig.pictureView" :on-close="closeViewer" :url-list="[dig.picurl]" />
import ElImageViewer from 'element-ui/packages/image/src/image-viewer';
components: { commonDialog, ElImageViewer },
然后就是点击图片文件名称下载文件流进行转码,转成可以查看的src。
// 查看图片
async pictureView(row) {
let res = await this.axios({
method: "get",
url: `/service-file-app/app/file/download-id?id=${row.fileId}`,
interface: 1,
responseType: "arraybuffer" //这个是获取流必传的不然获取格式不成功
})
if (res.data) {
this.dig.picurl = 'data:image/jpeg;base64,' + this.arrayBufferToBase64(res.data) // 进行base64转码
this.dig.pictureView = true
} else {
}
},
// 关闭查看图片
closeViewer() {
this.dig.pictureView = false
},
// 二进制流转码url
arrayBufferToBase64(buffer) {
let binary = ''
let bytes = new Uint8Array(buffer)
let len = bytes.byteLength
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i])
}
return window.btoa(binary)
},
效果图如下:
最后就是pdf的预览功能:
// 查看PDF
async PDFView(row) {
let res = await this.axios({
method: "get",
url: `/service-file-app/app/file/download-id?id=${row.fileId}`,
interface: 1,
responseType: "blob",
headers: {
"Content-Type": "application/pdf",
},
})
if (res.data) {
let blob = new Blob([res.data], {
type: 'application/pdf;charset=utf-8'
}); // 这一步也是必须的,否则打开页面是一堆乱码
window.open(URL.createObjectURL(blob)) // 其实可以在页面内用object标签内嵌一个pdf浏览图出来,但是产品说直接打开新的页面好一点0.0
} else {
}
},
效果图如下: