封装el-upload组件,可直接使用,持续更新完善中

2,000 阅读1分钟

自己封装el-upload组件,可直接使用,持续更新完善中

子组件:

 <div class="imgList">
      <div v-if="showImages">
        <div
          class="img"
          v-show="item.url"
          v-for="(item, index) in filesList"
          :key="index"
          draggable="true"
          @dragstart="dragstartEventImg($event, index)" // 用于拖拽时的方法用于调换图片位置
          @dragenter="dragenterEventImg($event, index)" // 用于拖拽时的方法用于调换图片位置
          @dragend="dragendEventImg($event, index)" // 用于拖拽时的方法用于调换图片位置
          @dragover="dragoverEventImg" // 用于拖拽时的方法用于调换图片位置
        >
          <img :src="item.url" alt="" @click="lookBigImg(item.url)" /> //点击看大图

          <i
            v-if="canDelete"
            class="el-icon-error"
            @click="deleteImg(item.url)"
          ></i>
        </div>
      </div>
      <div
        class="uploadImg"
        :class="{ disabledStyle: disabled }"
        v-show="maxLength > filesList.length"
      >
        <el-upload
          :disabled="disabled" // 是否禁止上传
          :multiple="true" // 是否可上传多张
          name="files" 
          ref="imageUpload"
          :headers="headers" // 放请求头
          :before-upload="beforeUploadImg" // 图片上传前
          :data="{ fileType: 1 }" // 额外参数上传类型
          :show-file-list="false" // 是否显示已上传文件列表,默认样式如下图选择false为自定义已上传文件列表
          :action="uploadUrl" // 上传接口
          :on-success="uploadImg" // 图片上传成功的回调
          :limit="maxLength" // 最多上传多少张
          :file-list="filesList" // 已上传图片的列表不设置的话limit检测不了会导致删除图片后上传按钮无法点击
          :on-progress="progress" // 上传时的钩子可检测上传到百分之多少
          :on-exceed="onExceed" // 选择的文件超出限制就触发
          :on-error="onError" // 上传失败触发
        >
          <div :disabled="disabled" class="uploadBtn" v-if="type === 0">
            <i class="el-icon-plus"></i>
          </div>
          <el-button
            :disabled="disabled"
            size="small"
            class="normal"
            v-else-if="type === 1"
            >上传文件</el-button
          >
        </el-upload>
      </div>
      <div class="uploading" v-if="showLoading" v-show="progressShow">
        <div class="left">
          <i class="el-icon-paperclip"></i>
        </div>
        <div class="right">
          <div class="right-top">
            <span>{{ fileName }}</span>
            <i class="el-icon-close"  @click="cancelUpload = true"></i>
          </div>
          <div class="right-bottom">
            <el-progress
              :percentage="percentage"
              :format="format"
              :stroke-width="2"
              :status="status"
            ></el-progress>
          </div>
        </div>
      </div>
    </div>
下面贴上js代码
export default {
  props: {
  //是否展示上传时的loading
    showLoading: {
      type: Boolean,
      default: true,
    },
    maxLength: {
      // 可上传的最大数量
      type: Number,
      default: 1,
    },
    // 图片集合
    filesList: {
      type: Array,
      default: () => [],
    },
    // 上传按钮样式类型
    type: {
      type: Number,
      default: 0,
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false,
    },
    // 是否可删除图片
    canDelete: {
      type: Boolean,
      default: true,
    },
    // 是否展示图片
    showImages: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      uploadUrl: `${baseUrl}/common/uploadFile`, //上传的接口
      headers: { Authorization: localStorage.getItem('token') },
      upImgList: [],
      percentage: 0,
      fileName: '',
      status: null,
      progressShow: false,
      showBigImg: '',
      dialogVisible: false,
      tempArr: [],
      startImgIndex: '', //拖动前图片index
      endImgIndex: '', // 结束拖动的index
      cancelUpload: false,
    }
  },
  mounted() {
    this.upImgList = this.filesList
  },
  watch: {
    filesList(val) {
      this.upImgList = val
    },
  },
  methods: {
    // 拖动开始
    dragstartEventImg($event, index) {
      this.startImgIndex = index
    },
    // 拖动时
    dragenterEventImg($event, index) {
      this.endImgIndex = index
    },
    // 拖动结束
    dragendEventImg($event, index) {
      const currRow = this.upImgList.splice(this.startImgIndex, 1)[0]
      this.upImgList.splice(this.endImgIndex, 0, currRow)
      this.$emit('getImgList', this.upImgList)
    },
    // 放置
    dragoverEventImg(e) {
      e.preventDefault()
    },
    // 查看大图
    lookBigImg(url) {
      this.showBigImg = url
      this.dialogVisible = true
    },
    format(percentage) {
      return percentage === 100 ? '99%' : `${percentage}%` //防止到100时后端处理要时间,会卡在100一小段时间,优化体验
    },
    // 超出限制
    onExceed() {
      this.$message.error('选择的文件超出个数限制')
    },
    // 删除图片
    deleteImg(item) {
      for (let i = 0; i < this.upImgList.length; i++) {
        if (this.upImgList[i].url === item) {
          this.upImgList.splice(i, 1) // 将使后面的元素依次前移,数组长度减1
          i-- // 如果不减,将漏掉一个元素
        }
      }
      this.$emit('getImgList', this.upImgList)
    },
   // 上传时的钩子
    progress(event, file, fileList) {
      this.progressShow = true
      this.percentage = Math.ceil(event.percent)
      if (this.cancelUpload) {
        this.$refs.imageUpload.abort()
        this.$message.error('文件已取消上传')
        this.upImgList = this.upImgList.filter((item) => {
          return item.url
        })
        this.$emit('getImgList', this.upImgList) 
        this.progressShow = false
      }
    },
    // 上传失败
    onError(err, file, fileList) {
      this.upImgList.forEach((element, index) => {
        if (element.uid === file.uid) {
          this.upImgList.splice(index, 1) // 上传失败删除该记录
          this.$message.error('文件上传失败')
          this.$emit('getImgList', this.upImgList)
          this.progressShow = false
          this.status = null
          this.percentage = 0
          this.fileName = ''
        }
      })
    },
    //图片上传前
    beforeUploadImg(file) {
       this.cancelUpload = false
      let allowType = ['image/png', 'image/jpeg']
      if (allowType.indexOf(file.type) === -1) {
        this.$message.error('上传图片只能是 JPG、PNG 格式!')
        return false
      }
      if (file.size / 1024 / 1024 >= 3) {
        this.$message.error('只能上传小于3M的图片!')
        return false
      }
      this.fileName = file.name
      this.objAddItem(this.upImgList, file)
    },
    // 图片上传成功
    uploadImg(response, file, fileList) {
      let num = 0
      this.upImgList.forEach((item, index) => {
        if (item.uid === file.uid) {
          let ele = {
            uid: item.uid,
            url: response.data.fileUrl,
          }
          this.$set(this.upImgList, index, ele)
        }
        if (item.url === '') {
          num++
        }
      })

      this.$emit('getImgList', this.upImgList)
      if (num === 1) {
        this.progressShow = false //进度条消失
        this.status = null
        this.percentage = 0
        this.fileName = ''
      }
    },
    objAddItem(tempArr, file) {
      const tempObj = {
        uid: file.uid, // uid用于辨别文件
        url: '',
      }
      tempArr.push(tempObj)
    },
  },
}

样式部分

<style lang="scss" scoped>
.imgList {
  display: flex;
  flex-wrap: wrap;
  div {
    .img {
      position: relative;
      img {
        cursor: pointer;
        width: 64px;
        height: 64px;
        display: inline-block;
      }
      width: 64px;
      height: 64px;
      display: inline-block;
      margin-right: 8px;
      .el-icon-error {
        font-size: 16px;
        position: absolute;
        right: -8px;
        top: -8px;
        color: red;
      }
    }
  }
}

.normal {
  &:hover {
    color: #5d8eff !important ;
    background-color: #fff !important  ;
    border-color: #5d8eff !important ;
  }
  &::before {
    content: '';
    background-image: url('@/assets/images/upload2.png');
    background-size: 14px 14px;
    display: inline-block;
    width: 14px;
    height: 14px;
    transform: translateY(2px);
    margin-right: 6px;
  }
}

.uploadBtn {
  width: 64px;
  height: 64px;
  background: #f7f8fa;
  border: 1px solid #ebebe8;
  position: relative;
  i {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: #bebec5;
    font-size: 24px;
  }
}
.uploading {
  display: flex;
  width: 162px;
  margin-left: 8px;
  margin-top: 28px;
  .left {
    margin-right: 8px;
    i {
      display: inline-block;
      width: 14px;
      height: 14px;
      color: #000;
    }
  }
  .right {
    width: 140px;
    .right-top {
      display: flex;
      justify-content: space-between;
      span {
        height: 22px;
        font-size: 14px;
        font-weight: 400;
        color: rgba(0, 0, 0, 0.45);
        line-height: 22px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        width: 130px;
      }
    }
  }
  .el-icon-close {
    line-height: 22px;
  }
}
.disabledStyle {
  cursor: not-allowed;
}
</style>

父组件使用:

 <uploadImg
   :maxLength="6"
   :filesList="filesList"
   @getImgList="getImgList" // 数据更新时触发
 />

其他功能可根据子组件的props来设置