上传文件是项目里经常遇到的需求,我之前基本上是碰到的单个文件上传,最近的项目有多个文件同时上传的需求并下载,遂记录一下。
注意:文件上传时必须使用FormData形式传参。
以Element-UI为例:
点击上传
单个附件大小不超过20M
点击上传按钮选择文件(上传组件的使用方法请参考Element官网)
/* 选择上传文件 */
selectFile(file, fileList) {
this.fileList = fileList
this.fileList.map((item, index) => {
const fileSize = item.size / 1024 / 1024
if (fileSize > 20) {
this.$message.error('单个附件大小不能超过20M')
this.fileList.splice(index, 1)
}
})
},
将选择的文件保存到`fileList`数组中。有条件限制的可以在这处理。
我们知道上传文件时参数要用`FormData`形式传参,下一步就是把添加的文件放到`FormData`里面。
const fileData = new FormData()
this.fileList.map((file,index)=>{
// data_report为请求接口时的参数,将文件存放到此参数中,多个文件会有多个data_report参数
// 这里添加的是file.raw,file格式文件(二进制)
fileData.append('data_report', file.raw)
}
)
例如,我一次上传两个文件,如图:
当然有时候上传接口不止一个文件参数,还有其它参数,我们要把它们拼接起来。
const params = {
...this.form, // 表单数据
parent_data: JSON.stringify(this.form.parent_data),// 其它参数
creator_username: getUserInfo().name, // 其它参数
job_num: getUserInfo().job_num, // 其它参数
user_id: getUserInfo().userId // 其它参数
}
然后把上面的参数储存到`fileData`中
// 参数合并
for (const key in params) {
fileData.append(key, params[key])
}
// 现在`fileData`里包含了上传的文件参数和其它参数
最后就可以调用接口了
API.createList(fileData).then(async res => {
// TODO
})
下载时怎么监听进度呢?
首先我们在封装下载接口时添加一个配置对象config,然后要指定服务器返回的数据类型:
// 下载附件
export function downloadFile(data, config = {}) {
return request({
url: '/workflows/download_file/',
method: 'post',
data,
responseType: 'blob', // 表明服务器返回的数据类型(文件流的形式)
...config // config对象主要用来添加上传/下载附件监听
})
}
点击下载按钮请求接口:
/* 下载附件 */
downloadFile(item) {
const that = this
const params = {
path: item.path
}
API.downloadFile(params,
{ // 文件下载监听
onDownloadProgress(progress) {
const loading = that.$loading({
lock: true,
text: '下载中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
// 下载进度
const percent = Math.round((progress.loaded / progress.total) * 100) + '%'
if (percent === '100%') {
loading.close()
}
}
}
).then(res => { // 以流的形式返回的,这里没有code状态码
const blob = new Blob([res.data])
// 切割出文件名
const fileNameEncode = res.headers['content-disposition'].split('filename=')[1]
// 解码
let fileName = decodeURIComponent(fileNameEncode)
// 解码后的文件名会首尾多_,截取掉
fileName = fileName.substring(1, fileName.length - 1)
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, fileName)
} else {
var link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = fileName
link.click()
// 释放内存
window.URL.revokeObjectURL(link.href)
}
})
},