Vue

Element UI Multi Upload Component

Based on Element UI

· 2 min read
Element UI Multi Upload Component

Based on Element UI

<template>
  <div
    class="uploader"
    :exceed="
      $props.value.length >= $props.limit ||
        (pending && $props.value.length === $props.limit - 1)
    "
  >
    <el-upload
      action=""
      list-type="picture-card"
      :on-success="handleOnUploadSuccess"
      :on-error="handleOnUploadError"
      :on-exceed="handleOnUploadExceed"
      :on-remove="handleOnRemove"
      :before-upload="handleBeforeUpload"
      :http-request="handleUploadHttpRequest"
      :file-list="$props.value"
      :on-preview="handlePreview"
      :show-file-list="true"
      :limit="$props.limit"
      accept="image/png,image/gif,image/jpg,image/jpeg"
    >
      <i class="el-icon-plus"></i>
    </el-upload>
    <ElImageViewer
      v-if="showViewer"
      :on-close="() => (showViewer = false)"
      :url-list="[viewerUrl]"
    ></ElImageViewer>
  </div>
</template>

<script>
import ElImageViewer from "element-ui/packages/image/src/image-viewer";
export default {
  components: { ElImageViewer },
  props: {
    value: { type: Array, default: () => [] },
    api: Function,
    fileName: { type: String, default: "file" },
    limit: { type: Number, default: 3 },
    size: { type: Number, default: 5 }
  },
  model: {
    prop: "value",
    event: "change"
  },
  data() {
    return {
      pending: false,
      viewerUrl: "",
      showViewer: false,
      attachmentFetching: true,
      attachmentUploading: false,
      attachmentTooLarge: false,
      attachmentUploadFormData: new FormData()
    };
  },
  methods: {
    handleOnUploadSuccess(response, file, fileList) {
      this.attachmentUploadFormData.delete(this.$props.fileName);
      this.attachmentUploading = false;
      this.$message.success("上传成功");
      fileList[fileList.length - 1].url = response.data;
      fileList[fileList.length - 1].isDefault = 1;
      this.$emit("change", fileList);
      this.pending = false;
    },
    handleOnUploadError(error) {
      this.attachmentUploadFormData.delete(this.$props.fileName);
      this.attachmentUploading = false;
      this.$message.error(error.msg || error);
      this.pending = false;
    },
    handleBeforeUpload(file) {
      const isLt2M = file.size / 1024 / 1024 < this.$props.size;
      if (!isLt2M) {
        this.attachmentTooLarge = true;
        this.$message.error(`上传图片大小不能超过 ${this.$props.size}MB!`);
        return false;
      }
      this.attachmentUploadFormData.append(this.$props.fileName, file);
      this.pending = true;
      return true;
    },
    handleOnUploadExceed() {
      this.$message.error(`最多只能上传 ${this.$props.limit} 个附件~`);
    },
    async handleUploadHttpRequest() {
      this.attachmentUploading = true;
      return this.$props
        .api(this.attachmentUploadFormData)
        .then(response => Promise.resolve(response))
        .catch(error => Promise.reject(error));
    },
    handlePreview(file) {
      this.viewerUrl = file.url;
      this.showViewer = true;
    },
    handleOnRemove(file, fileList) {
      if (this.attachmentTooLarge) {
        this.attachmentTooLarge = false;
        return;
      }
      this.$emit("change", fileList);
    }
  }
};
</script>

<style lang="scss" scoped>
.uploader {
  display: inline-block;
  width: 100%;
  &[exceed="true"] {
    ::v-deep {
      .el-upload.el-upload--picture-card {
        display: none;
      }
    }
  }
  ::v-deep {
    .el-upload-list__item-thumbnail{
      object-fit: cover;
    }
    .el-list-enter-active,
    .el-list-leave-active {
      transition: unset;
    }
    .el-list-enter,
    .el-list-leave-active {
      opacity: 0;
      transform: unset;
    }
  }
}
</style>

Related Articles

Vuex4 + Typescript
· 3 min read