背景

最近使用 element-uiupload 组件上传图片列表,发现当选择上传的图片出错时,会将上一张图片删除了。

效果如下:
在这里插入图片描述
代码:

<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)

大致思路如下:
对用户选择的图片进行判断,判断合格后才执行上传事件;不合格,则提示错误信息。

这里涉及到三点

  1. 判断的时机,on-change 事件

  2. 停止 upload 组件的选中文件后默认进行上传的功能。这个可用通过设置 auto-upload属性来关闭

    参数说明类型
    auto-upload是否在选取文件后立即进行上传boolean
  3. 判断通过后,怎么触发上传事件?可以通过 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>
Logo

前往低代码交流专区

更多推荐