vue element-ui 的 upload 组件上传图片列表出错后多删除了一张图片(原因分析及解决方法)
背景
最近使用 element-ui
的 upload
组件上传图片列表,发现当选择上传的图片出错时,会将上一张图片删除了。
效果如下:
代码:
<template>
<el-upload
:action="action"
:file-list="fileList"
list-type="picture"
:on-remove="handleRemove"
:before-upload="beforeUpload"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">
<p>1. 只能上传 jpg / png 文件,且不超过 500 kb;</p>
<p>2. 建议上传图片的长宽比为1.5 : 1;</p>
</div>
</el-upload>
</template>
<script>
export default {
name: "uploadImageList",
props: {
action: {
type: String,
},
imageUrlList: {
type: Array,
},
},
data() {
return {
fileList: [],
limit: 4,
};
},
watch: {
imageUrlList(list) {
this.fileList = [];
list.forEach((element) => {
this.fileList.push({
name: element,
url: `${this.$store.state.server_url}/upload/${element}`,
});
});
},
},
mounted() {
this.imageUrlList.forEach((element) => {
this.fileList.push({
name: element,
url: `${this.$store.state.server_url}/upload/${element}`,
});
});
},
methods: {
beforeUpload(file) {
const isJPG = file.type === "image/jpeg";
const isLt2M = file.size / 1024 / 1024 < 0.5;
if (!isJPG) {
this.$message.error("上传头像图片只能是 JPG 格式!");
}
if (!isLt2M) {
this.$message.error("上传图片大小不能超过 500 kb!");
}
return isJPG && isLt2M;
},
handleRemove(file) {
this.$emit("delUploadImage", file.name);
},
},
};
</script>
原因分析
上面代码中,在 beforeUpload
事件中添加用户上传文件的判断操作。但该事件放回 false
时,会自动终止上传事件。但是呢!由于 上传失败后,组件会自动执行 on-remove
事件。而我这里因为需求的原因设置on-remove
会触发父组件的 delUploadImage
事件,导致了多删除了一次。所以就用上面这种情况出现了。
要点:
当
beforeUpload
事件返回false
时,element-ui
组件upload
会自动执行一次on-remove
事件。
解决方法
那该怎么解决这个问题呢?
我这里有两种解决方法:
1. 不自定义 on-remove 事件
这一点就不用分析了。前面提到,出现这个的原因是系统自动调用了 on-remove
事件。不自定义 on-remove
事件,让系统执行默认的 on-remove
方法。也就不会出现冲突了。
2. 在 on-remove 事件中添加判断,区分已上传的图片和出错的图片
第一种方法虽然简单,但是很多情况下,不得不自定义 on-remove
事件。那这是我们就需要在 on-remove
事件做个判断了。判断如果要删除的文件是错误的文件,就不执行自定义的 on-remove
的方法。
例如:
因为上传成功的图片都会存放到 file-list
属性中,那我们只需判断要删除的图片是否在其中就好了。
handleRemove(file) {
if(this.imageUrlList.indexOf(file) > -1){
this.$emit("delUploadImage", file.name);
}
}
3. 不使用 beforeUpload 事件来判断上传文件是否符合要求
不适用 beforeUpload
来判断,那就不会自动执行 on-remove
事件。
那判断该在哪里进行了?
我们可以在用户选择文件后读取文件信息来进行判断,而不是在上传前来进行判断。可以在upload
组件的 on-change
事件中进行。
参数 | 说明 | 类型 |
---|---|---|
on-change | 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用 | function(file, fileList) |
大致思路如下:
对用户选择的图片进行判断,判断合格后才执行上传事件;不合格,则提示错误信息。
这里涉及到三点
-
判断的时机,
on-change
事件 -
停止
upload
组件的选中文件后默认进行上传的功能。这个可用通过设置auto-upload
属性来关闭参数 说明 类型 auto-upload 是否在选取文件后立即进行上传 boolean -
判断通过后,怎么触发上传事件?可以通过
submit
方法来实现。方法名 说明 参数 submit 手动上传文件列表 —
关于第三点,需要讲解一下如何调用 submit
方法:
upload 如何使用 Methods 里的方法
关于这一点,其实只要我们明白一点就行了。
element-ui
是什么?
element-ui
是 vue 的第三方组件库。
也就是说,upload
是一个组件。那我们想要在当前组件中调用 upload
的方法,不就变成了父组件调用子组件的方法的问题了吗?
更多关于 vue 父子组件的通讯可以参考:《Vue 的父组件和子组件之数据传输、方法互调》 、《Vue 组件间通讯之非父子组件间通讯——事件总线(EventBus)》
所以我们可以这么做:
<template>
<el-upload
ref="uploadList"
:action="action"
:file-list="fileList"
:auto-upload="false"
list-type="picture"
:on-change="change"
:on-remove="handleRemove"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">
<p>1. 只能上传 jpg / jpeg / png 文件,且不超过 500 kb;</p>
<p>2. 建议上传图片的长宽比为1.5 : 1;</p>
</div>
</el-upload>
</template>
<script>
export default {
name: "uploadImageList",
props: {
action: {
type: String,
},
imageUrlList: {
type: Array,
},
},
data() {
return {
fileList: [],
};
},
watch: {
imageUrlList(list) {
this.fileList = [];
list.forEach((element) => {
this.fileList.push({
name: element,
url: `${this.$store.state.server_url}/upload/${element}`,
});
});
},
},
mounted() {
this.imageUrlList.forEach((element) => {
this.fileList.push({
name: element,
url: `${this.$store.state.server_url}/upload/${element}`,
});
});
},
methods: {
change(file, fileList){
const typeList = ["image/jpeg","image/png", "image/jpg"]
const isLt2M = file.raw.size / 1024 / 1024 < 0.5;
if (typeList.indexOf(file.raw.type) < 0) {
this.$message.error("上传图片只能是 jpg / png / jpeg 格式!");
fileList.pop();
this.fileList = fileList;
return false;
}
if (!isLt2M) {
this.$message.error("上传图片大小不能超过 500 kb!");
fileList.pop();
this.fileList = fileList;
return false;
}
this.$refs['uploadList'].submit();
},
handleRemove(file) {
this.$emit("delUploadImage", file.name);
},
},
};
</script>
修改后,效果如下:
完整的组件代码如下:
<template>
<el-upload
ref="uploadList"
class="text-l"
:action="action"
:file-list="fileList"
:auto-upload="false"
list-type="picture"
:limit="limit"
:on-change="change"
:on-exceed="handleExceed"
:on-remove="handleRemove"
:on-success="handleSuccess"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">
<p>1. 只能上传 jpg / jpeg / png 文件,且不超过 500 kb;</p>
<p>2. 建议上传图片的长宽比为1.5 : 1;</p>
</div>
</el-upload>
</template>
<script>
export default {
name: "uploadImageList",
props: {
action: {
type: String,
},
imageUrlList: {
type: Array,
},
},
data() {
return {
fileList: [],
limit: 4,
};
},
watch: {
imageUrlList(list) {
this.fileList = [];
list.forEach((element) => {
this.fileList.push({
name: element,
url: `${this.$store.state.server_url}/upload/${element}`,
});
});
},
},
mounted() {
this.imageUrlList.forEach((element) => {
this.fileList.push({
name: element,
url: `${this.$store.state.server_url}/upload/${element}`,
});
});
},
methods: {
change(file, fileList){
const typeList = ["image/jpeg","image/png", "image/jpg"]
const isLt2M = file.raw.size / 1024 / 1024 < 0.5;
if (typeList.indexOf(file.raw.type) < 0) {
this.$message.error("上传图片只能是 jpg / png / jpeg 格式!");
fileList.pop();
this.fileList = fileList;
return false;
}
if (!isLt2M) {
this.$message.error("上传图片大小不能超过 500 kb!");
fileList.pop();
this.fileList = fileList;
return false;
}
this.$refs['uploadList'].submit();
},
handleExceed() {
this.$message({
message: `一个商品只能添加${this.limit}张图片。`,
type: "warning",
});
},
handleSuccess(res, file, fileList) {
console.log(fileList);
console.log(res);
fileList.forEach((element) => {
if (element.response) {
element.name = element.response.data;
this.imageUrlList.push(element.response.data);
}
});
this.$emit("updateImgSrcList", this.imageUrlList);
},
handleRemove(file) {
this.$emit("delUploadImage", file.name);
},
},
};
</script>
更多推荐
所有评论(0)