原有项目使用Vue框架和Element组件库,图片展示和下载功能可细分为:
1. 图片展示是将单个图片点击后,弹窗显示,用户选择保存则以服务端id命名保存至本地;
2.下载功能分为单个图片下载和批量下载
原有管理系统中增加上述功能,需要新增JSZip和FileSaver两个JS库,开发步骤如下:
安装JSZip和FileSaver
npm install jszip --save
npm install file-saver --save
JSZip 库用于处理和生成 ZIP 文件。主要用到该库中两个方法:
file
()是 JSZip
对象的一个方法,用于向 ZIP 文件中添加文件。它接受两个参数:要添加到 ZIP 文件中的文件名和文件内容;generateAsync()
用于异步生成 ZIP 文件。它返回一个 Promise,该 Promise 在 ZIP 文件生成完成后被解析。方法使用示例;const zip = new JSZip();
// 添加一个文件到 ZIP 中
zip.file("hello.txt", "Hello world!");
// 生成ZIP压缩文件的异步操作
zip.generateAsync({ type: "blob" })
.then((content) => {
// Do something
});
FileSaver 则用于将数据保存为文件。主要使用saveAs()方法,接受两个参数:要保存的文件名和要保存的数据。使用方法如下:[data]为二进制数据,将被保存到新创建image.jpg的本地文件中
const blob = new Blob( [data], {type : 'image/jpeg'} );
FileSaver.saveAs( blob, 'image.jpg' );
在页面中引入上述库
import JSZip from 'jszip'
import FileSaver from 'file-saver'
图片的展示和保存都需要提前获取图片,先完成单个图片请求。此处,需使用responseType: 'blob'
,因为图片是二进制数据,而不是文本数据。如果我们将responseType设置为'text',则浏览器会尝试将二进制数据解析为文本数据,这将导致数据损坏。通过将responseType设置为'blob',我们告诉浏览器将响应数据作为二进制对象处理,这样我们就可以正确地下载图片。
图片的签名信息获取,需要通过另外的接口get到,后续处理。此外,请求涉及到了跨域问题,通过Nginx代理解决,属于后端内容不再赘述。
// 单个图片下载
getFile(item) {
return new Promise((resolve, reject) => {
this.axios({
url: baseUrl + item.requestUrl,
method: 'get',
headers: {
'Authorization': item.authToken,
'Signature': item.reqSignature,
'ClientId': item.clientId
},
// 设置此选项,响应数据类型设置为blob(arraybuffer也OK);未设置时请求数据为乱码
responseType: 'blob'
}).then((response) => {
resolve(response) // 将下载的文件返回
}).catch((error) => {
reject(error.toString())
})
})
},
请求方法完成后,点击页面按钮触发showImage展示图片,此方法中调用getFile()获取图片,并显示在el-dialog弹窗中。实现中需要注意getFile()方法响应的数据是Blob对象,需要将其转换为url,以便赋值给el-image的src属性。
showImage(item) {
this.startLoading()
getImageTokenById({ idFaultResource: parseInt(item.value) }).then((resp) => {
console.log(JSON.stringify(resp))
if (resp.code === '200') {
const param = {
// resourceKey: resp.result.resourceKey,
requestUrl: resp.result.requestUrl,
authToken: resp.result.authToken,
reqSignature: resp.result.reqSignature,
clientId: resp.result.clientId
}
this.getFile(param).then((response) => {
this.endLoading()
this.dialogVisible = true
console.log(JSON.stringify(response))
// urlCreator用于创建URL对象。在浏览器中,window.URL和window.webkitURL对象可能存在一个或两个
const urlCreator = window.URL || window.webkitURL
// createObjectURL方法将一个Blob或MediaStream对象转换为URL,以便赋值给el-image的src属性
const imageUrl = urlCreator.createObjectURL(response.data)
console.log('URL::::' + JSON.stringify(imageUrl))
this.dialogImageUrl = imageUrl
this.dialogImageName = resp.result.resourceKey
this.imageBlob = [response.data]
}).catch((error) => {
this.$message({
showClose: true,
message: '获取图片失败,' + error,
type: 'error'
})
this.endLoading()
})
}
}).catch((error) => {
this.$message({
showClose: true,
message: error,
type: 'error'
})
this.endLoading()
})
},
注:getImageById()方法需要提前获取签名信息;
图片展示弹窗十分简单,添加标题,图片关闭按钮和下载按钮即可
点击下载图片调用saveAs()方法保存图片,将图片文件按照imageName命名保存,并隐藏弹窗。
saveImage(data, imageName) {
const blob = new Blob(data, { type: 'image/jpeg' })
FileSaver.saveAs(blob, imageName + '.jpg')
this.dialogImageUrl = ''
this.dialogVisible = false
this.$message({
showClose: true,
message: '图片下载完成!',
type: 'success'
})
},
批量下载只需要,将图片列表遍历逐个下载,待所有图片下载完成调用saveAs()方法保存并压缩生成文件夹。
// 批量导出图片
downloadFile() {
const zip = new JSZip()
const imagesPromises = []
const cache = {}
this.startLoading()
getImagesTokenById ({ idTrustOrder: this.idTrustOrder }).then((resp) => {
if (resp.code === '200') {
const imageList = resp.result.downloadImageList
if (imageList.length === 0) {
this.$message({
showClose: true,
message: '当前无可下载的故障内容!',
type: 'warning'
})
this.endLoading()
return
}
imageList.map((item) => {
const promise = this.getFile(item).then((resp) => {
// 逐个下载图片
console.log('获取的图片内容::' + item.resourceKey + '.jpg' + resp.data)
// 创建文件用file()方法,文件夹用floder()方法
zip.file(item.resourceKey + '.jpg', resp.data, { binary: true })
cache[item.resourceKey] = resp.data
})
imagesPromises.push(promise)
})
// 生成zip文件
Promise.all(imagesPromises)
.then(() => {
this.endLoading()
zip.generateAsync({
type: 'blob' // 文件格式
}).then((content) => {
// 生成二进制流
FileSaver.saveAs(content, '图片.zip') // 利用file-saver保存文件,自定义文件名图片.zip
this.$message({
showClose: true,
message: '文件下载完成!',
type: 'success'
})
})
})
.catch((error) => {
this.$message({
showClose: true,
message: '文件下载失败!' + error,
type: 'error'
})
this.endLoading()
})
}
}).catch((error) => {
this.$message({
showClose: true,
message: error,
type: 'error'
})
this.endLoading()
})
},
测试功能可用,开发中遇到的问题主要是跨域,二进制数据的处理,还有IT限制我的接口
参考文献:
1. JS实现根据URL批量下载文件并压缩成zip文件_javascript技巧_脚本之家