引言
在我们的日常开发中,上传文件是一个很普遍的需求。这时候大家使用Vue的都会想到el-upload这个组件,但我们的需求中,经常都是需要上传多个文件,传参等。此时就需要我们来使用他之中的http-request来做一个自定义上传。
上传文件较简单,可直接观看完整代码部分,一看即懂。上传请求见下图:
传统Form表单提交
文件上传分很多种方式,el-upload这一组件的上传呢,实质上使用的是form表单提交,一般上传都是给后端传二进制文件即可。
<input type="file" id="upload">
console.log($("#upload").files); => 即可拿到一个包含二进制文件的数组。
复制代码
但是这样的方式并不能满足我们的开发需求,他只能拿到该次上传的文件,且如果用户有增删文件或上传不符合规定的文件,都还需要我们进一步判断。
所以呢,我们可以直接使用el-upload组件,对其进行自定义上传,并使用其已经封装好的钩子函数。
el-upload的自定义上传
在组件中使用http-request这一属性,赋值即为我们的上传函数。再配合组件中的on-change,on-remove,来拿到我们需要的File。
// 采用form表单的提交方式
let formData = new FormData();
this.upload_List.forEach((item, index) => {
formData.append("file", FileXX); // 添加文件
});
因为append会添加一个新值到实例对象的一个已存在的键中,如果键不存在则会添加该键。
可以类似理解为=> file : [].push(xxx),所以无论是多个文件一次上传,或单个文件上传都可以使用该方式。
复制代码
1.避坑
在开发中,我发现:
(1)当删除文件时,该文件的raw为object,不是file。
(2)用户二次上传文件时,on-change中的形参filelist第二次上传的文件的raw为object,也不是file。
所以,在on-change,on-remove中,我们不能拿filelist直接赋值,而是要进行一个新数组的增删子项处理。
2.完整代码如下(包含了一些判断)
<el-upload
id="upload"
ref="upload"
drag
multiple
:limit="100"
:file-list="fileList"
action="#"
:http-request="Execute_File"
:auto-upload="false"
:on-change="upload_change"
:on-remove="upload_remove"
:on-exceed="upload_exceed"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">
将文件拖到此处,或
<em>点击选取</em>
</div>
</el-upload>
data(){
return {
fileList: [], //深拷贝,判断重名及第一步时的文件信息展示
upload_List: [], //上传的file,
notifyPromise: Promise.resolve() // 解决Notification组件的高度塌陷问题
};
}
methods:{
upload_change: function(file, fileList) {
// 判断 > 1M
if (file.size > 1048576) {
fileList.pop();
let msg_size = `您上传的${file.name},该文件大于1M,请您重新上传。`;
this.notify_self(msg_size, "size");
return false;
}
// 判断重名文件
let repeat_judge = this.fileList.find(item => {
return item.name == file.name;
});
if (repeat_judge) {
fileList.pop();
let msg_repeat = `您上传的${file.name},该文件有重名文件,请您重新上传。`;
this.notify_self(msg_repeat, "repeat");
return false;
}
this.fileList = JSON.parse(JSON.stringify(fileList));
this.upload_List.push(file);
},
upload_remove(file, fileList) {
this.fileList = JSON.parse(JSON.stringify(fileList));
// 不直接赋值是因为打印出来的数据中,如果多个文件删至只剩一个时,该文件的raw为object,不是file
this.upload_List.forEach((item, index) => {
if (item.name == file.name) {
this.upload_List.splice(index, 1);
}
});
},
upload_exceed(files, fileList) {
this.$alert("您最多只能上传100个文件!", "上传文件", {
confirmButtonText: "确定",
type: "warning"
});
},
notify_self(msg, type) {
this.notifyPromise = this.notifyPromise.then(this.$nextTick).then(() => {
this.$notify({
title: `${type == "size" ? "文件大于1M" : "文件重名"}`,
message: msg,
iconClass: `${
type == "size" ? "el-icon-s-opportunity" : "el-icon-message-solid"
}`,
customClass: `${type == "size" ? "notify_size" : "notify_repeat"}`,
duration: 6000
});
});
},
Execute_File() {
// 传输文件
let formData = new FormData();
this.upload_List.forEach((item, index) => {
formData.append("file", item.raw);
});
$.axios({
url:"XXX",
method:"post",
data: formData,
params:{
test1:"1",
test2:"2"
} //传参
}).then(res = > { })
.catch(res = > { })
},
}
复制代码
3.Notification组件。组件的高度塌陷的问题
插播一个题外话~ ,在上传文件判断时,如果不合规定我们是通过element的Notification组件来提示,但该组件是存在一个高度塌陷的问题的。
data(){
notifyPromise: Promise.resolve()
},
this.notifyPromise = this.notifyPromise.then(this.$nextTick).then(() => {
this.$notify({
title: "111111",
message: "22222",
});
});
复制代码
这个解决方法是百度得来的,嘿嘿, 原博客链接:element-ui Notification重叠问题,原因及解决办法 我的理解是通过Promise将其变为同步操作流程,通过this.$nextTick来获取更新后的dom状态,dom更新完之后,再执行Notification组件。
emmm 说实话,我没懂他这里这种语法糖的写法,在我的理解中,上面这种写法实际上是下方这个流程,但是我这样改写了之后,没起作用。有大哥理解的话,麻烦评论区留言,指导一下。
this.notifyPromise = new Promise((resolve, reject) => {
resolve();
})
.then(() => {
return new Promise((resolve, reject) => {
this.$nextTick(() => {
resolve();
});
});
})
.then(() => {
this.$notify({
title: "111111",
message: "22222"
});
});
复制代码
尾言
好人一生平安,给弟弟点个赞吧 ~