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

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

    自定义http-request方法

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

    1. <el-upload :action="getFileUrl()"
    2.      name='uploadFile'
    3.     accept='image/*'
    4.      multiple
    5.         :http-request="myUpload"
    6.         :file-list="picList"
    7.         list-type="picture-card"
    8.         :on-remove='handlePicSuccessRemove'
    9.      :on-success="handlePicSuccessAdd">
    10.      <class="el-icon-plus"></i>
    11. </el-upload>
    12. <script>
    13. export default{
    14.     methods:{
    15.         myUpload(content){
    16.              let formData = new FormData();
    17.             formData.append(content.filename, content.file);
    18.             axios.post(content.action, formData,{ 'Content-Type':'multipart/form-data' }).then(response => {
    19.                     if(response.data.errcode=='200'){//正确
    20.                         content.onSuccess(response.data)
    21.                     }else{//出错
    22.                         content.onError(response.data);
    23.                         Message.error({
    24.                             message: response.data.errMsg
    25.                         });
    26.                     }
    27.                 }).catch(response => {
    28.                 });
    29.         },
    30.     }
    31. }
    32. </script>

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

    上传进度条

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

    1. <el-upload :action="getFileUrl()"
    2.      name='uploadFile'
    3.     accept='image/*'
    4.      multiple
    5.         :http-request="myUpload"
    6.         :file-list="picList"
    7.         list-type="picture-card"
    8.         :on-remove='handlePicSuccessRemove'
    9.      :on-success="handlePicSuccessAdd">
    10.      <class="el-icon-plus"></i>
    11. </el-upload>
    12. <script>
    13. export default{
    14.     methods:{
    15.         myUpload(content){
    16.              let formData = new FormData();
    17.             formData.append(content.filename, content.file);
    18.             axios.post(content.action, formData,{
    19.                     headers:{'Content-Type':'multipart/form-data'},
    20.                     onUploadProgress:process=>{//增加了进度条的显示
    21.                     const percentCompleted = Math.floor((process.loaded * 100) / process.total);
    22.                     content.onProgress({ percent: percentCompleted });
    23.                     }
    24.                 }).then(response => {
    25.                     if(response.data.errcode=='200'){//正确
    26.                         content.onSuccess(response.data)
    27.                     }else{//出错
    28.                         content.onError(response.data);
    29.                         Message.error({
    30.                             message: response.data.errMsg
    31.                         });
    32.                     }
    33.                 }).catch(response => {
    34.                 });
    35.         },
    36.     }
    37. }
    38. </script>

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

    取消上传

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

    1. <el-upload :action="getFileUrl()"
    2.      name='uploadFile'
    3.     accept='image/*'
    4.      multiple
    5.         :http-request="myUpload"
    6.         :before-remove='myBeforeRemove'
    7.         :file-list="picList"
    8.         list-type="picture-card"
    9.         :on-remove='handlePicSuccessRemove'
    10.      :on-success="handlePicSuccessAdd">
    11.      <class="el-icon-plus"></i>
    12. </el-upload>
    13. <script>
    14. export default{
    15.     data(){
    16.         return {
    17.             cancelMap:{},//取消列表
    18.         }
    19.     },
    20.     methods:{
    21.         myBeforeRemove(file,fileList){//移除前取消axios
    22.             let fn=this.cancelMap[file.uid];
    23.             if(fn){
    24.                 fn('cancel');
    25.                 delete this.cancelMap[file.uid];
    26.             }
    27.         },
    28.         myUpload(content){
    29.              let formData = new FormData();
    30.             formData.append(content.filename, content.file);
    31.             var CancelToken = axios.CancelToken;//获取axios取消对象
    32.             var source = CancelToken.source();
    33.             this.cancelMap[content.file.uid]=source.cancel;//记录取消请求
    34.             axios.post(content.action, formData,{
    35.                     headers:{'Content-Type':'multipart/form-data'},
    36.                     cancelToken: source.token,
    37.                     onUploadProgress:process=>{//增加了进度条的显示
    38.                     const percentCompleted = Math.floor((process.loaded * 100) / process.total);
    39.                     content.onProgress({ percent: percentCompleted });
    40.                     }
    41.                 }).then(response => {
    42.         delete this.cancelMap[content.file.uid];
    43.                     if(response.data.errcode=='200'){//正确
    44.                         content.onSuccess(response.data)
    45.                     }else{//出错
    46.                         content.onError(response.data);
    47.                         Message.error({
    48.                             message: response.data.errMsg
    49.                         });
    50.                     }
    51.                 }).catch(response => {
    52.                 });
    53.         },
    54.     }
    55. }
    56. </script>

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

    上传失败后继续上传

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

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

    1. <el-upload :action="getFileUrl()"
    2.      name='uploadFile'
    3.     accept='image/*'
    4.      multiple
    5.         :http-request="myUpload"
    6.         :before-remove='myBeforeRemove'
    7.         :file-list="picList"
    8.         list-type="picture-card"
    9.         :on-remove='handlePicSuccessRemove'
    10.      :on-success="handlePicSuccessAdd">
    11.      <class="el-icon-plus"></i>
    12. </el-upload>
    13. <script>
    14. export default{
    15.     data(){
    16.         return {
    17.             cancelMap:{},//取消列表
    18.         }
    19.     },
    20.     methods:{
    21.         myBeforeRemove(file,fileList){//移除前取消axios
    22.             let fn=this.cancelMap[file.uid];
    23.             if(fn){
    24.                 fn('cancel');
    25.                 delete this.cancelMap[file.uid];
    26.             }
    27.         },
    28.         myUpload(content){
    29.              let formData = new FormData();
    30.             formData.append(content.filename, content.file);
    31.             var CancelToken = axios.CancelToken;//获取axios取消对象
    32.             var source = CancelToken.source();
    33.             this.cancelMap[content.file.uid]=source.cancel;//记录取消请求
    34.             axios.post(content.action, formData,{
    35.                     headers:{'Content-Type':'multipart/form-data'},
    36.                     cancelToken: source.token,
    37.                     onUploadProgress:process=>{//增加了进度条的显示
    38.                     const percentCompleted = Math.floor((process.loaded * 100) / process.total);
    39.                     content.onProgress({ percent: percentCompleted });
    40.                     }
    41.                 }).then(response => {
    42.         delete this.cancelMap[content.file.uid];
    43.                     if(response.data.errcode=='200'){//正确
    44.                         content.onSuccess(response.data)
    45.                     }else{//出错
    46.                         if(response.data.data.faileType==-1){//已知的超时报错
    47.                             this.myUpload(content);//继续上传
    48.                         }else{//已知的其他错误
    49.                             content.onError(response.data);
    50.                             Message.error({
    51.                                 message: response.data.errMsg
    52.                             });
    53.                         }
    54.                     }
    55.                 }).catch(response => {//http报错
    56.         delete this.cancelMap[content.file.uid];
    57.                     if(response.message=='cancel'){//取消的时候也会http错误
    58.                     }else{//http504之类的超时报错
    59.                         this.myUpload(content);//继续上传
    60.                     }
    61.                 });
    62.         },
    63.     }
    64. }
    65. </script>

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

    回到顶部
    我要评论

    所有评论

      相关文章