el-upload多选封装上传组件,灵活性强可自定义

背景:element-ui:2.15.13,平时写el-upload需要每次都写success、beforeupload、remove等函数很繁琐,而且遇到循环表单上传还要处理非常麻烦,所以我把上传组件进行封装,支持直接v-model双向绑定,不需要在考虑上传逻辑

一.新建上传组件

新建aLiYunUpload.vue文件,直接cv使用,需要注意的地方我都有注释

<template>
  <div class="zzh_aLiYunUpload">
    <el-upload
      style="width: 100%;"
      ref="upload"
      class="zzh_aLiYunUpload"
      :http-request="handleUpload"
      action
      :limit="limit"
      :multiple="true"
      :file-list="fileList"
      :before-upload="onBeforeUpload.bind(null)"
      :on-success="onFileSuccess.bind(null)"
      :on-remove="onRemove.bind(null)"
      :on-preview="handlePreview.bind(null)"
      :on-exceed="onExceed.bind(null)"
      size="small"
      :list-type="listType"
      :drag="listType == 'drag'"
      :disabled="disabled"
      :class="{ disabled: fileList.length >= limit, hideDefaultList: hideDefaultList }"
    >
      <slot name="button">
        <el-button size="small" type="primary" v-if="listType == ''">
          <i class="el-icon-upload2"></i>
          点击上传
        </el-button>
        <i class="el-icon-plus" v-if="listType == 'picture-card'"></i>
        <i v-if="listType == 'drag'" class="el-icon-upload"></i>
        <div v-if="listType == 'drag'" class="el-upload__text">
          将文件拖到此处,或
          <em>点击上传</em>
        </div>
      </slot>
    </el-upload>
    <!-- <aLiYunUpload style="width: 90%;" v-model="ruleForm.files" :limit="20" fileType="file"></aLiYunUpload> -->
  </div>
</template>

<script>
import upload from '@/utils/fileUpload.js'; //上传的函数或者接口,因为我这里走的前端oss,如果调后端接口上传同理
export default {
  name: 'zzh_aLiYunUpload',
  props: {
    value: {
      type: Array,
      default: () => [],
    },
    //文件最大值  (单位M)
    maxSize: {
      type: Number,
      default: 100,
    },
    //最多上传几个文件
    limit: {
      type: Number,
      default: 1,
    },
    //同el-upload listType属性
    listType: {
      type: String,
      default: '', //显示  drag:拖拽上传   picture-card:图片按钮  默认是文字上传按钮
    },
    props: {
      type: Object,
      default: () => {
        return {
          url: 'url', //自定义url
          name: 'name', //自定义name
          key: 'Id', //假如后端需要保存Id之类的 配一下key
        };
      },
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    //自定义支持的校验类型
    supportType: {
      type: Array,
      default: () => [],
    },
    //隐藏默认list,方便自定义
    hideDefaultList: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      fileList: [], //文件
    };
  },
  methods: {
    handlePreview(file) {
      let fileType = file.name
        .split('.')
        .pop()
        .toLowerCase();
      if (['txt'].includes(fileType)) {
        const req = new XMLHttpRequest();
        req.open('get', file.url, true);
        req.responseType = 'blob';
        req.setRequestHeader('Content-Type', 'application/json');
        req.onload = function() {
          // 这里因为没有对返回的数据处理编码格式,所以在预览txt时需要转换成utf-8
          const data = new Blob([req.response], { type: 'application/json;charset=utf-8' });
          let blobUrl = window.URL.createObjectURL(data);
          window.open(blobUrl);
        };
        req.send();
        return;
      } else if (['zip', 'rar', 'ai', 'psd'].includes(fileType)) {
        return this.download(file);
      } else if (['jpg', 'jpeg', 'gif', 'png', 'tif', 'bmp'].includes(fileType)) {
        return window.open(file.url);
      } else if (['pdf', 'PDF'].includes(fileType)) {
        return window.open(file.url);
      } else if (['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx'].includes(fileType)) {
        return window.open(`https://view.officeapps.live.com/op/embed.aspx?src=${file.url}&wdAccPdf=1&wdDownloadButton=True'`);
      } else {
        return window.open(file.url);
      }
    },
    download(file) {
      //   file = file.response;
      var x = new XMLHttpRequest();
      x.open('GET', file.url, true);
      x.responseType = 'blob';
      x.onload = function(e) {
        var url = window.URL.createObjectURL(x.response);
        const link = document.createElement('a');
        link.target = '_blank';
        link.href = url;
        link.download = file.name;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
      };
      x.send();
    },
    onBeforeUpload(file) {
      if (file.size / 1024 / 1024 > this.maxSize) {
        this.$message.warning(`文件大小不超过${this.maxSize}M`);
        return false;
      }
      let typeList;
      // if (this.fileType == 'image') {
      //   typeList = ['jpg', 'jpeg', 'gif', 'bmp', 'png', 'tif'];
      //   if (
      //     !typeList.includes(
      //       file.name
      //         .split('.')
      //         .pop()
      //         .toLowerCase()
      //     )
      //   ) {
      //     this.$message.warning(`请检查上传的类型是否为${typeList.toString()}`);
      //     return false;
      //   }
      // }
      //  else {
      //   typeList = ['jpg', 'jpeg', 'gif', 'bmp', 'png', 'tif', 'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'pdf', 'zip', 'rar', 'txt', 'ai', 'psd'];
      // }
      if (this.supportType && this.supportType.length) {
        typeList = this.supportType;
        if (
          !typeList.includes(
            file.name
              .split('.')
              .pop()
              .toLowerCase()
          )
        ) {
          this.$message.warning(`请检查上传的类型是否为${typeList.toString()}`);
          return false;
        }
      }
    },
    // 自定义上传操作
    handleUpload(op) {
      //   this.uploadDisabled = true;
      //************只需要修改这里的上传函数就行了 */
      upload(
        op.file,
        res => {
          //*******拿到接口返回的值,这里返回格式根据自己项目调整,然后拼接一个name和url的对象调用一下op.onSuccess */
          let temp = {
            name: res.attachment,
            url: res.host + '/' + res.aliyunAddress,
          };
          this.host = res.host;
          op.onSuccess(temp);
        },
        err => {
          console.log(err);
          //   this.uploadDisabled = false;
        },
        res => {
          this.uploadDisabled = false;
        }
      );
    },
    onFileSuccess(response, file, fileList) {
      //   console.log(fileList);
      const statusColumn = fileList.filter(val => val && val.status !== 'success');
      if (!statusColumn.length) {
        this.fileList = fileList.map(item => {
          return {
            name: item.name,
            url: item.response ? item.response.url : item.url,
            [this.props.key]: item[this.props.key],
          };
        });
        console.log('🚀this.fileList |', JSON.parse(JSON.stringify(this.fileList)));
        this.$emit('input', this.getList(this.fileList));
        this.$emit('change', this.getList(this.fileList));
      }
    },
    onRemove(file, fileList) {
      this.fileList.forEach((v, i) => {
        if (v.url === file.url) {
          this.fileList.splice(i, 1);
          this.$emit('input', this.getList(this.fileList));
          this.$emit('change', this.getList(this.fileList));
        }
      });
    },
    //超出文件上传数量
    onExceed() {
      this.$message.warning(`最多只能上传${this.limit}个文件`);
      return false;
    },
    //#endregion
    getList(arr) {
      // 处理返回的文件格式
      return arr.map(val => {
        return {
          [this.props.url]: val.url,
          [this.props.name]: val.name,
          [this.props.key]: val[this.props.key],
        };
      });
    },
  },
  created() {},
  mounted() {},
  watch: {
    value: {
      handler(newVal) {
        this.fileList = this.value.map(item => {
          return {
            url: item[this.props.url],
            name: item[this.props.name],
            [this.props.key]: item[this.props.key],
          };
        });
      },
      deep: true,
      immediate: true,
    },
  },
};
</script>

<style lang="less">
.zzh_aLiYunUpload {
  .disabled .el-upload--picture-card {
    display: none !important;
  }
  .disabled .el-upload-- {
    display: none !important;
  }
  .el-upload-list__item.is-ready {
    display: none;
  }
  .el-upload-list__item {
    transition: none !important;
    -webkit-transition: none !important;
  }
  .el-upload-list__item-name {
    transition: none !important;
    -webkit-transition: none !important;
  }
  .hideDefaultList {
    .el-upload-list,
    .el-upload__tip {
      display: none !important;
    }
  }
}
</style>

 只需要关注一下自定义上传,调函数或者接口,然后拿到返回值调用一下op.onSuccess就行

二、使用组件

import 然后compoment注册我就不说了,如果项目用的地方多的话,建议直接全局注册,比较方便

1.常规使用

   <aLiYunUpload style="width: 90%;" v-model="ruleForm.files" :limit="20" @input="input" @change="change"></aLiYunUpload>

 

直接v-model双向绑定就行,默认是[{url:xxx,name:xxx}]格式,另外内置了input和change函数根据需要使用

2.和默认el-upload或者这样相同样式,只需要传一个listType,同el-upload的listType,配置可以设置单个文件的最大值maxSize,上传个数limit单个就传1,多个就传数字,包括数组绑定的类型,如接口想要这个格式[{fileUrl:xxx,fileName}],都相应配置就行,可以在props自行参考扩展

 <aLiYunUpload style="width: 90%;" v-model="ruleForm.files" :limit="20" :maxSize="1024" listType="picture-card" :props="{ url: 'fileUrl', name: 'fileName' }" ></aLiYunUpload>

3.完全自定义样式和上传按钮,这里的supportType默认不传不限制类型,传数组则只能上传指定类型

上传按钮可以传一个插槽slot=button自定义,传一个 hideDefaultList=true即可隐藏默认的list列表 自己根据需要去循环写样式,然后绑定函数可参考我的方式,就不需要重复写相应逻辑

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值