index.vue 6.79 KB
<template>
  <div class="component-upload-image">
    <div v-if="false" class="imgBox">
      <div
        v-for="item in fileList"
        :key="item.url"
        class="imgItem"
      >
        <div class="dot">X</div>
        <img
          :src="item.url"
        >
      </div>
    </div>
    <el-upload
      multiple
      :accept="accept"
      :action="uploadFileUrl"
      list-type="picture-card"
      :on-success="handleUploadSuccess"
      :before-upload="handleBeforeUpload"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      name="file"
      :on-remove="handleRemove"
      :show-file-list="true"
      :headers="headers"
      :file-list="fileList"
      :on-preview="handlePictureCardPreview"
      :class="{hide: this.fileList.length >= this.limit}"
    >
      <i class="el-icon-plus" />
    </el-upload>

    <!-- 上传提示 -->
    <div
      v-if="showTip"
      slot="tip"
      class="el-upload__tip"
    >
      请上传
      <template v-if="fileSize"> 大小不超过 <b style="color: #3F9B6A">{{ fileSize }}MB</b></template>
      <template v-if="fileType"> 格式为 <b style="color: #3F9B6A">{{ fileType.join('/') }}</b></template>
      的文件
    </div>

    <el-dialog
      :visible.sync="dialogVisible"
      title="预览"
      width="800"
      append-to-body
    >
      <img
        :src="dialogImageUrl"
        style="display: block; max-width: 100%; margin: 0 auto"
      >
    </el-dialog>
  </div>
</template>

<script>
// import { getAccessToken } from '@/utils/auth'
import { uploadUrl } from '@/utils/request'
export default {
  props: {
    value: [String, Object, Array],
    // 图片数量限制
    limit: {
      type: Number,
      default: 5
    },
    // 允许上传的文件类型,例如:'image/*,video/*'
      accept: {
        type: String,
        default: 'image/*'
      },
    // 大小限制(MB)
    fileSize: {
      type: Number,
      default: 5
    },
    // 文件类型, 例如['png', 'jpg', 'mp4']
    fileType: {
      type: Array,
      default: () => ['png', 'jpg', 'mp4']
    },
    // 是否显示提示
    isShowTip: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      number: 0,
      uploadList: [],
      dialogImageUrl: '',
      dialogVisible: false,
      hideUpload: false,
      uploadFileUrl: uploadUrl, // 请求地址
      headers: { Authorization: '' }, // 设置上传的请求头部
      fileList: []
    }
  },
  computed: {
    // 是否显示提示
    showTip () {
      return this.isShowTip && (this.fileType || this.fileSize)
    }
  },
  watch: {
    value: {
      handler (val) {
        if (val) {
          // 首先将值转为数组
          const list = Array.isArray(val) ? val : this.value.split(',')
          // 然后将数组转为对象数组
          this.fileList = list.map(item => {
            if (typeof item === 'string') {
              item = { name: item, url: item }
            }
            return item
          })
        } else {
          this.fileList = []
          return []
        }
      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    // 删除图片
    handleRemove (file, fileList) {
      const findex = this.fileList.map(f => f.name).indexOf(file.name)
      if (findex > -1) {
        this.fileList.splice(findex, 1)
        this.$emit('input', this.listToString(this.fileList))
      }
    },
    // 上传成功回调
    handleUploadSuccess (res) {
      this.uploadList.push({ name: res.data.url, url: res.data.url })
      console.log(this.uploadList)
      if (this.uploadList.length === this.number) {
        this.fileList = this.fileList.concat(this.uploadList)
        this.uploadList = []
        this.number = 0
        this.$emit('input', this.listToString(this.fileList))
        // this.$modal.closeLoading()
      }
    },
    // 上传前loading加载
    handleBeforeUpload (file) {
       let isSupported = false;
      let isImg = false
      if (this.fileType.length) {
        let fileExtension = ''
        if (file.name.lastIndexOf('.') > -1) {
          fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
        }
        isImg = this.fileType.some(type => {
          if (file.type.indexOf(type) > -1) return true
          if (fileExtension && fileExtension.indexOf(type) > -1) return true
          return false
        })
      } else {
        isImg = file.type.indexOf('image') > -1
      }
       // if (this.accept.includes('image/*')) {
       //    isSupported = file.type.indexOf('image') > -1;
       //  }
       //  if (this.accept.includes('video/*')) {
       //    isSupported = file.type.indexOf('video') > -1;
       //  }

      if (!isImg) {
        this.$message.error(`文件格式不正确, 请上传${this.fileType.join('/')}图片或者视频格式文件!`)
        return false
      }
      if (this.fileSize) {
        const isLt = file.size / 1024 / 1024 < this.fileSize
        if (!isLt) {
          this.$message.error(`上传头像图片大小不能超过 ${this.fileSize} MB!`)
          return false
        }
      }
      this.$message.warning('正在上传图片,请稍候...')
      this.number++
    },
    // 文件个数超出
    handleExceed () {
      this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`)
    },
    // 上传失败
    handleUploadError () {
      this.$message.error('上传图片失败,请重试')
      // this.$modal.closeLoading()
    },
    // 预览
    handlePictureCardPreview (file) {
      this.dialogImageUrl = file.url
      this.dialogVisible = true
    },
    // 对象转成指定字符串分隔
    listToString (list, separator) {
      let strs = ''
      separator = separator || ','
      for (const i in list) {
        strs += list[i].url.replace(this.baseUrl, '') + separator
      }
      return strs !== '' ? strs.substr(0, strs.length - 1) : ''
    }
  }
}
</script>
<style
    scoped
    lang="scss"
>
// .el-upload--picture-card 控制加号部分
::v-deep.hide .el-upload--picture-card {
  display: none;
}

// 去掉动画效果
::v-deep .el-list-enter-active,
::v-deep .el-list-leave-active {
  transition: all 0s;
}

::v-deep .el-list-enter, .el-list-leave-active {
  opacity: 0;
  transform: translateY(0);
}

.imgBox {
  display: flex;
  flex-wrap: wrap;

  .imgItem {
    position: relative;
    width: 100px;
    height: 100px;
    .dot {
      position: absolute;
      right: -10px;
      top: -10px;
      width: 20px;
      height: 20px;
      color: #fff;
      background-color: red;
      text-align: center;
      line-height: 20px;
      border-radius: 50%;
      cursor: pointer;
    }

    img {
      width: 100%;
      height: 100%;
      margin-right: 5px;
      margin-bottom: 5px;
      display: inline-block;
    }
  }
}
.el-upload__tip{
    position: absolute;
    left: 150px;
    top: 70px;
}
</style>