el-upload 多文件 上传 只执行一次成功回调on-success的问题

一、问题背景**

  • 背景:使用element的上传组件,在使用多文件上传时,发现如果同时选择两个文件,上传完成之后,upload组件的列表只显示一个文件。
  • 通过查看控制台发现on-success方法在上传文件时,只执行了一次。返回的两个文件,其中一个状态是uploading。而我们取文件又只取了status是success的文件。

二、探索和解决**

1,解除绑定upload组件的file-list绑定(非根本解决)
这个方法简单粗暴,通过自己验证确实是可以的。不会出现选择多个文件上传,最后只有一个生效的问题。但是这个解决方法有个弊端就是说,当我们需要数据回显时,upload组件的flie-list并没有绑定数据,所以不会渲染出来。
2,通过绑定初始变量,实际操作使用另一个变量(根本解决);
第二种方法是:我们可以通过定义两个变量:
一个赋初值给upload组件,仅仅只是作为展示使用;
一个是真实我们要操控的变量,所有的对于文件的操作,包括上传和删除都对这个变量进行操作
贴一下关键代码

<template>
  <el-dialog :title="title" :visible.sync="dialogVisible" width="60%">
    <upload-file
      type="file"
      :upload-success="uploadSuccess"
      :remove="updateFileList"
      :file-list="fileList"
      :limit-count="5"
      :limit-size="10"
      ref="uploadFile"
    ></upload-file>
  </el-dialog>
</template>

<script>
import { MESSAGE_API } from '@/api';
import UploadFile from '@/components/upload-file';

export default {
  name: 'property-dialog',
  model: {
    prop: 'dialogVisible',
    event: 'change'
  },
  components: {
    UploadFile
  },
  props: {
    dialogVisible: {
      type: Boolean,
      default: false
    },
    options: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      fileList: [], //fileList仅仅作为展示使用
      realFileList: [] // 所有关于文件的上传和删除直接操作 realFileList。
    };
  },
  methods: {
    dialogCancel() {
      this.$emit('change', false);
    },
    updateFileList(file) {
      // 剔除被删除的文件
      this.realFileList = this.realFileList.filter(v => v.path !== file.path);
    },

    async uploadSuccess(result, file) {
      // 对于上传成功的文件 只保存到realFileList
      if (result.success) {
        const { fileName, path, fileSize } = file.response.data;
        const fileObj = {
          fileName,
          path,
          fileSize,
          name: fileName
        };

        this.realFileList.push(fileObj);
      }
    },

    async dialogSubmit(){
      // 提交文件 attachments 也是提交 realFileList
      const attachments = this.realFileList;
      console.log(`attachments`, attachments)
      this.$emit('change', false);
    },
    async getDetail(){
      const { id, areaCode, appCode } = this.options.colum;
      const result = await MESSAGE_API.getEmailDetail({ id, areaCode, appCode });
      const { attachmentRequest } = result.data;
      // 获取数据对两个文件列表都进行赋值
      this.fileList = attachmentRequest ? attachmentRequest.attachments.map(v => ({ ...v, name: v.fileName })) : [];
      this.realFileList = attachmentRequest ? attachmentRequest.attachments.map(v => ({ ...v, name: v.fileName })) : [];
    }
  }
};
</script>

封装的upload组件,如果需要可以自取

<template lang="html">
  <div class="upload-file">
    <el-upload
      :action="url"
      :headers="headers"
      :before-upload="beforeUpload"
      :on-success="uploadSuccess"
      :on-preview="isPicture ? onPreview : download"
      :on-remove="remove"
      :before-remove="beforeRemove"
      :on-exceed="onExceed"
      :list-type="listType"
      :accept="accept"
      :file-list="fileList"
      :limit="limitCount"
      :disabled="disabled"
      :class="[isHideUpload && 'hide-upload-button', disabled && 'operate-disabled', uploadClassName]"
      multiple
      ref="elUpload"
    >
      <template v-if="isPicture">
        <i class="el-icon-plus"></i>
      </template>

      <template v-else>
        <el-button :disabled="disabled" size="small" type="primary">{{uploadText}}</el-button>
      </template>

      <div slot="tip" class="el-upload__tip">{{ tip }}</div>
    </el-upload>

    <image-viewer-s v-show="dialogVisible" :on-close="closeViewer" :url-list="[dialogImageUrl]"></image-viewer-s>

  </div>
</template>

<script>
import Cookies from 'js-cookie';

const API_HOST = process.env.VUE_APP_API_HOST;
const PREFIX = process.env.VUE_APP_PUBLIC_API_EMAIL_PREFIX;
const APP_CODE = process.env.VUE_APP_APP_CODE;

const TOKEN_KEY = process.env.VUE_APP_TOKEN_KEY;

export default {
  name: 'upload-file',
  props: {
    type: {
      type: String,
      default: 'file' // file/picture
    },
    limitCount: {
      type: Number,
      default: 1
    },
    limitSize: {
      type: Number,
      default: 5 // 单位 M
    },
    fileList: {
      type: Array,
      default: () => ([])
    },
    uploadSuccess: {
      type: Function,
      default: () => {}
    },
    remove: {
      type: Function,
      default: () => {}
    },
    download: {
      type: Function,
      default: () => {}
    },
    previewImg: {
      type: Function,
      default: () => {}
    },
    tip: {
      type: String,
      default: ''
    },
    uploadClassName: {
      type: String,
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    },
    uploadText: {
      type: String,
      default: '+ Upload'
    }
  },
  data() {
    return {
      url: `${API_HOST}${PREFIX}/file/uploadFile`,
      dialogImageUrl: '',
      dialogVisible: false
    };
  },
  computed: {
    headers() {
      return {
        Authorization: Cookies.get(TOKEN_KEY),
        appCode: APP_CODE
      };
    },
    isPicture() {
      return this.type === 'picture';
    },
    accept() {
      return this.isPicture ? 'image/*' : '';
    },
    listType() {
      return this.isPicture ? 'picture-card' : 'text';
    },
    isHideUpload() {
      return this.fileList.length >= this.limitCount;
    }
  },
  methods: {
    onExceed(files, fileList) {
      this.$message.warning(`No more than ${ this.limitCount } files, you have selected ${files.length} files, total ${files.length + fileList.length} files`);
    },
    async onPreview(file) {
      const { url } = file;
      if (url.includes('base64')) {
        this.dialogImageUrl = url;
      } else {
        this.dialogImageUrl = await this.previewImg(file.response.data);
      }

      this.dialogVisible = true;
    },
    beforeUpload(file) {
      const { size } = file;
      if (this.isOverSize(size)) {
        this.$message.error(`The file size is ${(size / 1024 / 1024).toFixed(2)}M,over ${this.limitSize}M`);
        return false;
      }
    },
    beforeRemove(file) {
      const { size } = file;
      if (!this.isOverSize(size)) {
        return this.$confirm(`Delete ${ file.name }?`);
      }
    },
    isOverSize(size) {
      if (size / 1024 / 1024 < this.limitSize) {
        return false;
      }
      return true;
    },
    closeViewer() {
      this.dialogVisible = false;
    },
    clearFiles() {
      this.$refs.elUpload.clearFiles();
    }
  }
};
</script>

<style lang="scss" scoped>
.upload-file {
  .operate-disabled {
    /deep/.el-upload--picture-card {
      background-color: #F5F7FA;
      border-color: #E4E7ED;
      color: #C0C4CC;
      cursor: not-allowed;

      &:hover,
      &:focus {
        border-color: #E4E7ED;
      }
    }
  }
}
</style>

三、总结

问题的解决是一个探索的过程。当然这么说也有点问题,实际的方案并不是自己出的,而是通过求助网友。自己只是把问题的解决方案拿出来,分享给大家,互助共赢。感谢这个大佬。
https://blog.csdn.net/qq_41780372/article/details/117773863

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值