Elementui中有一个el_upload(上传组件),这个组件还比较好用,它可以支持多图上传,并且自带管理功能(例如进度,删除,添加等功能)。

但是这个组件在判断图片是否上传成功的问题上有些问题,它认为的成功是你调了上传图片的接口,然后只要返回的状态吗是200之类的就表示成功,但是接口报错可能返回的状态也是200,通过内部的字段标示这个上传失败了,这种情况下el_upload还会认为图片上传成功了,但其实已经失败了。因此需要自定义el_upload的上传行为。

自定义http-request方法

这个需要自定义http-request方法:

<el-upload :action="getFileUrl()"
     name='uploadFile'
    accept='image/*'
     multiple
        :http-request="myUpload"
        :file-list="picList"
        list-type="picture-card"
        :on-remove='handlePicSuccessRemove'
     :on-success="handlePicSuccessAdd">
     <i class="el-icon-plus"></i>
</el-upload>
<script>
export default{
    methods:{
        myUpload(content){
             let formData = new FormData();
            formData.append(content.filename, content.file);
            axios.post(content.action, formData,{ 'Content-Type':'multipart/form-data' }).then(response => {
                    if(response.data.errcode=='200'){//正确
                        content.onSuccess(response.data)
                    }else{//出错
                        content.onError(response.data);
                        Message.error({
                            message: response.data.errMsg
                        });
                    }
                }).catch(response => {
                });
        },
    }
}
</script>

方法内部通过onSuccess()和onError()方法判断上传是否报错。注意onSuccess()和onError()中要将请求的response.data传递下去,否则你写的:on-success和:on-error将接受不到参数。

上传进度条

我们会发现上面我们改写后,上传图片就没有进度条了,因此我们要再加上一个进度条:

<el-upload :action="getFileUrl()"
     name='uploadFile'
    accept='image/*'
     multiple
        :http-request="myUpload"
        :file-list="picList"
        list-type="picture-card"
        :on-remove='handlePicSuccessRemove'
     :on-success="handlePicSuccessAdd">
     <i class="el-icon-plus"></i>
</el-upload>
<script>
export default{
    methods:{
        myUpload(content){
             let formData = new FormData();
            formData.append(content.filename, content.file);
            axios.post(content.action, formData,{
                    headers:{'Content-Type':'multipart/form-data'},
                    onUploadProgress:process=>{//增加了进度条的显示
                    const percentCompleted = Math.floor((process.loaded * 100) / process.total);
                    content.onProgress({ percent: percentCompleted });
                    }
                }).then(response => {
                    if(response.data.errcode=='200'){//正确
                        content.onSuccess(response.data)
                    }else{//出错
                        content.onError(response.data);
                        Message.error({
                            message: response.data.errMsg
                        });
                    }
                }).catch(response => {
                });
        },
    }
}
</script>

我们先通过axois中的onUploadProgress事件当前的进度,然后组装成一个{percent:80}这种结构传递给onProcess方法。

取消上传

我们改写后,会发现现在删除元素不会取消接口了,默认是有的,因此我们要加上删除元素取消上传的功能:

<el-upload :action="getFileUrl()"
     name='uploadFile'
    accept='image/*'
     multiple
        :http-request="myUpload"
        :before-remove='myBeforeRemove'
        :file-list="picList"
        list-type="picture-card"
        :on-remove='handlePicSuccessRemove'
     :on-success="handlePicSuccessAdd">
     <i class="el-icon-plus"></i>
</el-upload>
<script>
export default{
    data(){
        return {
            cancelMap:{},//取消列表
        }
    },
    methods:{
        myBeforeRemove(file,fileList){//移除前取消axios
            let fn=this.cancelMap[file.uid];
            if(fn){
                fn('cancel');
                delete this.cancelMap[file.uid];
            }
        },
        myUpload(content){
             let formData = new FormData();
            formData.append(content.filename, content.file);
            var CancelToken = axios.CancelToken;//获取axios取消对象
            var source = CancelToken.source();
            this.cancelMap[content.file.uid]=source.cancel;//记录取消请求
            axios.post(content.action, formData,{
                    headers:{'Content-Type':'multipart/form-data'},
                    cancelToken: source.token,
                    onUploadProgress:process=>{//增加了进度条的显示
                    const percentCompleted = Math.floor((process.loaded * 100) / process.total);
                    content.onProgress({ percent: percentCompleted });
                    }
                }).then(response => {
        delete this.cancelMap[content.file.uid];
                    if(response.data.errcode=='200'){//正确
                        content.onSuccess(response.data)
                    }else{//出错
                        content.onError(response.data);
                        Message.error({
                            message: response.data.errMsg
                        });
                    }
                }).catch(response => {
                });
        },
    }
}
</script>

这个功能比较麻烦,利用一个map记录当前上传的接口,通过content.file.uid来获取唯一的上传文件id,然后将axios的取消方法放进去,在:before-remove事件中拦截,如果这个file的uid在map中存在,就要调用取消上传的方法。

上传失败后继续上传

这里还可能会出现一种情况,就是一次上传很多的图片(例如7,80张),可能会导致某些图片的上传失败了(服务器处理不过来之类的情况),我遇到过三种形式的报错,一种是正常返回200,内部字段超时报错;还有一种是HTTP为504之类的服务器超时;还有一种是客户端超时cancel(被动cancel)。

这种时候我们希望将失败的图片继续上传:

<el-upload :action="getFileUrl()"
     name='uploadFile'
    accept='image/*'
     multiple
        :http-request="myUpload"
        :before-remove='myBeforeRemove'
        :file-list="picList"
        list-type="picture-card"
        :on-remove='handlePicSuccessRemove'
     :on-success="handlePicSuccessAdd">
     <i class="el-icon-plus"></i>
</el-upload>
<script>
export default{
    data(){
        return {
            cancelMap:{},//取消列表
        }
    },
    methods:{
        myBeforeRemove(file,fileList){//移除前取消axios
            let fn=this.cancelMap[file.uid];
            if(fn){
                fn('cancel');
                delete this.cancelMap[file.uid];
            }
        },
        myUpload(content){
             let formData = new FormData();
            formData.append(content.filename, content.file);
            var CancelToken = axios.CancelToken;//获取axios取消对象
            var source = CancelToken.source();
            this.cancelMap[content.file.uid]=source.cancel;//记录取消请求
            axios.post(content.action, formData,{
                    headers:{'Content-Type':'multipart/form-data'},
                    cancelToken: source.token,
                    onUploadProgress:process=>{//增加了进度条的显示
                    const percentCompleted = Math.floor((process.loaded * 100) / process.total);
                    content.onProgress({ percent: percentCompleted });
                    }
                }).then(response => {
        delete this.cancelMap[content.file.uid];
                    if(response.data.errcode=='200'){//正确
                        content.onSuccess(response.data)
                    }else{//出错
                        if(response.data.data.faileType==-1){//已知的超时报错
                            this.myUpload(content);//继续上传
                        }else{//已知的其他错误
                            content.onError(response.data);
                            Message.error({
                                message: response.data.errMsg
                            });
                        }
                    }
                }).catch(response => {//http报错
        delete this.cancelMap[content.file.uid];
                    if(response.message=='cancel'){//取消的时候也会http错误
                    }else{//http504之类的超时报错
                        this.myUpload(content);//继续上传
                    }
                });
        },
    }
}
</script>

这里只需要在myUpload的请求失败方法中识别出正常上传失败的情况,以及http上传失败的情况。例如在http报错中的cancel(主动取消),就是取消上传,也会报http报错,但是它不用继续上传。

回到顶部
我要评论

所有评论

返回
邮箱:
绑定
取消
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

邮箱:
绑定邮箱后,若有回复,会邮件通知。
提交
还可以输入500个字