vue element 封装上传组件(图片、文件)

1、新建封装组件components/upload.vue

<template>
  <div class="uploadImgBox">
    <el-upload v-bind="localOptions" action="" ref="upload" :disabled="localDisabled" :uploadText="uploadText"
      :show-file-list="showFileList" :file-list="localFileList" :http-request="httpRequest" :on-exceed="handleExceed"
      :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :before-upload="beforeUpload"
      :on-change="handleChange" :class="{hide: uploadHide}">
      <!-- :before-remove="beforeRemove" -->
      <el-button v-if="localOptions.listType === 'text'" size="small" type="primary" icon="el-icon-upload2">{{uploadText
        || '上传文件'}}</el-button>
      <i v-else class="el-icon-plus"></i>
    </el-upload>
    <el-dialog v-if="localOptions.listType === 'picture-card'" class="preview-dialog" :visible.sync="visible">
      <img :src="previewUrl" style="z-index: 9 !important;" />
    </el-dialog>
  </div>
</template>
<script>
  /**
   * 将图片字符串转换为数组(上传组件专用)
   */
  const stringToFileList = str => {
    let list = [];
    if (typeof str === "string" && str) {
      list = str.split(",").map((url, i) => {
        const name = url.split("/").pop();
        const uid = name.split(".")[0] + i;
        return { url, name, uid };
      });
    }
    return list;
  };
  // 接口 oss签名
  import { goodDevelopOssPolicy } from "@/api/goods.js";
  import $request from "@/api/axios";
  export default {
    props: {
      disabled: {
        type: Boolean,
        default: false
      },
      uploadOptions: {
        type: Object,
        default: () => ({})
      },
      fileList: {
        type: [Array, String],
        default: () => []
      },
      uploadText: {
        type: String,
        default: ''
      },
      showFileList: {
        type: Boolean,
        default: true
      },
    },

    data() {
      return {
        previewUrl: "",
        visible: false,
        localFileList: []
      };
    },
    computed: {
      localDisabled() {
        return this.disabled || this.localOptions.disabled;
      },
      localOptions() {
        let obj = {
          // 上传列表的内建样式: text/ picture/ picture-card
          listType: "text",
          // 一次上传多个
          multiple: false,
          // 显示列表
          showUploadList: true,
          // 默认列表最大数量
          limit: 1,
          // 图片大小:M
          size: 1.5,
          // 上传类型校验
          type: null,
          // 组件model的参数
          key: null,
          disabled: false,
          // 文件名参数
          // hasFileName: false,
          // 隐藏按钮,即只展示列表
          hiddenBtn: false,
          // 只允许图片上传
          onlyImage: null
        };
        const item = JSON.parse(JSON.stringify(this.uploadOptions));
        // delete item.type;
        delete item.data;
        // 当设置为图片时,默认先设置1个
        if (item.listType === "picture-card" && item.limit === 1) {
          obj.limit = 1;
          obj.onlyImage = true;
        }
        Object.assign(obj, item);
        return obj;
      },
      uploadHide() {
        return this.localFileList.length === this.localOptions.limit;
      }
    },
    watch: {
      fileList: {
        handler(list) {
          if (Array.isArray(list)) {
            this.localFileList = list;
          } else {
            this.localFileList = stringToFileList(list);
            Object.assign(this.localFileList, stringToFileList(list));
          }
        },
        deep: true,
        immediate: true
      }
    },
    methods: {
      // 改变
      handleChange(file, fileList) {
        if (file.raw.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.raw.type === 'application/vnd.ms-excel' || file.raw.type === 'application/pdf') {
          if (this.$refs['upload'].elForm) {
            this.$refs['upload'].elForm.clearValidate()
          }
        }
      },
      // 自定义接口
      httpRequest(data) {
        const { localOptions: { key, limit }, $message: { success, error } } = this, file = data.file;
        // 转义上传文件名不能被识别
        let params = { dir: "common" }, fileName = file.name.replace(/[\+,#,$,?,@,(),;,:,%]/g, "_");
        // fileName = encodeURIComponent(file.name)
        goodDevelopOssPolicy(params).then(res => {
          let url = "xxxxxxxxxxxxxxxxxxxxxxxxx"; // 上传阿里云的接口
          let idx = fileName.indexOf(".");
          let ossData = new FormData();
          let keyValue = fileName.substr(0, idx) + new Date().getTime() + fileName.substr(idx);
          const newFile = {
            uid: file.uid,
            name: file.name,
            size: file.size,
            url: ""
          };
          ossData.append("ossaccessKeyId", res.accessid);
          ossData.append("key", "common/" + keyValue);
          ossData.append("policy", res.policy);
          ossData.append("signature", res.signature);
          ossData.append("dir", res.dir);
          ossData.append("host", url);
          ossData.append("file", file);
          $request({
            url,
            method: "POST",
            headers: {
              "Content-Type": "multipart/form-data",
              Authorization: sessionStorage.getItem("Cookie")
            },
            data: ossData
          }).then(() => {
            newFile.url = `${url}/${params.dir}/${keyValue}`;
            this.localFileList = limit === 1 ? [newFile] : [...this.localFileList, newFile];
            this.loading = false;
            this.$emit("upload-success", {
              file: newFile,
              fileList: this.localFileList,
              key
            });
          });
        })
      },

      //  超出限制
      handleExceed(files, fileList) {
        const {
          localOptions: { limit },
          $message: { warning }
        } = this;
        warning(`当前限制选择 ${limit} 个文件,本次选择了 ${files.length
          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
        );
      },

      // 点击预览图片
      handlePictureCardPreview(file) {
        this.visible = true;
        this.previewUrl = file && file.url;
      },
      // 删除上传图片
      handleRemove(file, fileList) {
        if (file.status === 'success') {
          const index = this.localFileList.indexOf(file);
          const newFileList = this.localFileList.slice();
          newFileList.splice(index, 1);
          this.localFileList = newFileList;
          this.$emit("upload-success", {
            file,
            fileList: newFileList,
            key: this.localOptions.key
          });
        }
      },
      // 上传之前
      beforeUpload(file, fileList) {
        // 限制上传文件类型与大小
        const isImg = file.type === 'image/jpeg' || file.type === 'image/jpg' || file.type === 'image/png' || file.type === 'image/bmp';
        if(this.localOptions.listType === 'picture-card') {
           if (!isImg) {
             this.$message.error('上传图片格式为.jpg/.png/.jpeg/.bmp');
             return false
           }
         } 
         const isFile = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.type === 'application/vnd.ms-excel' || file.type === 'application/pdf';
         if(this.localOptions.listType === 'text') {
           if (!isFile) {
             this.$message.error('上传文件格式为.pdf/.xls/.xlsx');
             return false
           }
         }
        const isLt30M = (file.size / 1024 / 1024) < 30;
        if (!isLt30M) {
          this.$message.error('上传文件大小不能超过 30MB!');
          return false
        }
      },
      // 移除之前
      beforeRemove(file, fileList) {
        return this.$confirm(`确定移除 ${file.name}?`);
      }
    }
  };
</script>
<style lang="less" scoped>
  //去除动画
  .el-list-enter-active,
  .el-list-leave-active {
    transition: all 0s;
  }

  /deep/.el-upload {
    position: relative;

    .el-icon-plus {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
  }

  /deep/.el-upload--picture-card {
    background-color: #fbfdff;
    border: 1px dashed #c0ccda;
    border-radius: 6px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    width: 64px;
    height: 64px;
    cursor: pointer;
    line-height: 98px;
    vertical-align: top;
  }

  /deep/.el-upload-list--picture-card .el-upload-list__item {
    overflow: hidden;
    background-color: #fff;
    border: 1px solid #c0ccda;
    border-radius: 6px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    width: 64px;
    height: 64px;
    margin: 0 8px 8px 0;
    display: inline-block;
  }

  /deep/.el-dialog {
    max-width: 80vh;
    max-height: 80vh;

    .el-dialog__header {
      display: none;
    }
  }

  /deep/.hide .el-upload--picture-card {
    display: none;
  }
</style>

2、在使用上传功能的地方引入封装组件

<script>
  // 上传文件
  import upload from '@/components/upload.vue'
  export default {
    components: {
      // 上传文件
      upload,
    },
    data(){
        return {}
    }
  }
</script>

3、使用

// 单图上传 listType:'text'上传文件,listType:'picture-card'上传图片,listType:文件类型,limit:限制上传数量, key: 唯一值

<template v-slot:img="scope">
  <upload :upload-options="{listType: 'picture-card', limit: 1, key: scope.row.key}"
     :file-list="scope.row.img" @upload-success="handleFileUrl">
  </upload>
</template>
// 赋值 this.ruleForm.imgData
handleFileUrl(data) {
  this.ruleForm.imgData.forEach((item, index) => {
    if(item.key == data.key) {
      this.ruleForm.imgData[index].img = (data && data.fileList && data.fileList[0] &&         
         data.fileList[0].url) || ""
    }
  })
},



// 多图上传 listType:文件类型,limit:限制上传数量, multiple: 允许多张上传

<upload :upload-options="{listType: 'picture-card', limit: 10, multiple: true}"
  :file-list="ruleForm.img" @upload-success="handleImgPath">
 </upload>

// 赋值 this.ruleForm.imgStr
handleImgPath(data) {
  let imgArr = []
  data && data.fileList.forEach(item => {
    imgArr.push(item.url)
  })
  this.ruleForm.imgStr = imgArr.toString()
},

4、效果展示

单图展示:

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值