core net vue 图片上传_VUE自定义图片上传组件

ac99fac9cb1b5d7fc2e720ab773f7401.png

在使用elementUI的Upload上传组件中,发现了一些问题,比如并不需要上传过程中的动画效果,如果想去掉,组件并没有提供简单的参数设置,需要自己添加css去掉动画效果。

.el-upload-list__item {
   transition: none;
 }
 .el-list-enter-to,
 .el-list-leave-to,
 .el-list-enter-active,
 .el-list-leave-active,
 .el-list-move,
 .is-ready {
    display: none;
 }

但是如果想要自定义已上传图片的删除按钮,或者需要自定义缩略图长宽比时,就发现根本改不了,因此需要自己动手图片上传组件。

1、支持自定义缩略图大小。

2、支持自定义上传图片大小。

3、支持自定义图片格式。

4、支持自定义图片展示效果(目前使用了v-viewer)。

5、支持图片拖拽排序。

HTML部分:

<template>
  <div ref="uploadWrap" class="upload-wrap">
    <div class="images-viewer" v-viewer>
      <div
        class="image-li"
        v-for="(file, index) in pictureCard.fileList"
        :style="`height: ${thumbnailHeight + 2}px`"
        :key="index"
      >
        <i class="icon-delete-bg"></i>
        <i
          class="icon-delete el-icon-error"
          @click="handleRemove(file, index)"
        ></i>
        <img
          :width="thumbnailWidth"
          :height="thumbnailHeight"
          draggable="true"
          @dragend="e => handleDragEnd(e, index)"
          @dragstart="e => handleDragStart(e, index)"
          :data-source="file.url"
          :src="
            `${file.url}?x-oss-process=image/resize,m_fixed,h_${thumbnailHeight},w_${thumbnailWidth}/sharpen,100`
          "
        />
      </div>
    </div>
    <div
      class="progress-wrap"
      v-show="isUpload"
      :style="
        `padding-top: ${(thumbnailHeight - thumbnailWidth) / 2}px;
         height: ${thumbnailHeight + 2}px`
      "
    >
      <el-progress
        :width="
          thumbnailWidth > thumbnailHeight ? thumbnailHeight : thumbnailWidth
        "
        type="circle"
        :percentage="uploadPercentage"
      ></el-progress>
    </div>
    <div
      class="upload-plus"
      v-show="!isUpload"
      @click="handleAdd"
      v-if="pictureCard.fileList.length < limit"
      :style="
        `width: ${thumbnailWidth}px;height: ${thumbnailHeight}px;line-height: ${thumbnailHeight}px`
      "
    >
      <i class="el-icon-plus icon-add"></i>
      <input
        type="file"
        name="file"
        ref="inputFile"
        :multiple="this.multiple"
        :accept="this.accept"
        @change="handleChange"
        class="upload-wrap-input"
      />
    </div>
  </div>
</template>

JS部分(图片上传接口使用了阿里云OSS):

<script type="text/ecmascript-6">
export default {
  name: 'Upload',
  components: {},
  props: {
    // 文件大小限制
    fileSize: {
      type: Number,
      default: 50
    },
    // 是否支持多选
    multiple: {
      type: Boolean,
      default: false
    },
    // 缩略图尺寸宽
    thumbnailWidth: {
      type: Number,
      default: 100
    },
    // 缩略图尺寸高
    thumbnailHeight: {
      type: Number,
      default: 100
    },
    // 可上传的图片类型
    accept: {
      type: String,
      default: "image/jpeg,image/jpg,image/png,,image/gif"
    },
    // 展示方式
    type: {
      type: String,
      default: "picture-card"
    },
    // 图片限制数量
    limit: {
      type: Number,
      default: 1
    },
    // 上传列表
    fileLists: {
      type: Array,
      default: () => {
        return []
      }
    }
  },
  data () {
    return {
      startX: 0,
      startY: 0,
      uploadPercentage: 0,
      isUpload: false,
      pictureCard:{
        fileList: [],
      },
      uploadQueue: []
    }
  },
  watch: {
    // fileLists异步更新
    fileLists(){
      this.pictureCard.fileList = this.fileLists
    },
    // 处理批量上传
    uploadQueue(){
      if(this.uploadQueue.length > 0){
        this.uploadFunc()
      }
    }
  },
  mounted () {
    if(this.type === 'picture-card'){
      this.pictureCard.fileList = this.fileLists
    }
  },
  methods: {
    // 开始拖拽图片
    handleDragStart(e, index){
      this.startX = e.x
      this.startY = e.y
    },
    // 结束拖拽图片
    handleDragEnd(e, index){
      const moveX = e.x - this.startX
      const moveY = e.y - this.startY
      const width = this.thumbnailWidth + 10
      const height = this.thumbnailHeight + 10
      let wrapWidth = 0
      if(this.$refs.uploadWrap){
        wrapWidth = this.$refs.uploadWrap.offsetWidth
      }else{
        return
      }
      const rowNum = Math.floor(wrapWidth/width)
      let numX = moveX > 0 ? Math.round(moveX/width) : Math.abs(Math.floor(moveX/width))
      let numY = moveY > 0 ? Math.round(moveY/height) : Math.ceil(moveY/height)
      let insertIndex = index
      if(index < rowNum && numX < rowNum && numY < 0){
        return
      }
      if(moveX > 0 && numX > 0){
        insertIndex += numX - 1
      }else if(moveX <= 0 && numX > 0){
        insertIndex -= numX
      }
      insertIndex += rowNum * numY
      this.pictureCardMove(index, insertIndex)
    },
    // 图片位置移动
    pictureCardMove(index, insertIndex){
      insertIndex = insertIndex < 0 ? 0 : insertIndex
      insertIndex = insertIndex > this.pictureCard.fileList.length ? this.pictureCard.fileList.length : insertIndex
      const item = this.pictureCard.fileList.splice(index, 1)[0]
      this.pictureCard.fileList.splice(insertIndex, 0, item)
    },
    // 上传文件
    handleChange(file){
      if(file.target && file.target.files){
        if(file.target.files.length > this.limit + this.pictureCard.fileList.length){
          this.handleExceed()
          return
        }
        let totalLth = 0
        let $file = {}
        for( let i = 0 ; i < file.target.files.length ; i ++){
          totalLth = this.pictureCard.fileList.length + this.uploadQueue.length
          $file = file.target.files[i]
          if(totalLth < this.limit){
            if($file.size > this.fileSize * 1024 * 1024){
              this.$message({
                type: 'error',
                message: `文件“${$file.name}”大小超过${this.fileSize}M,不能上传`
              })
            }else{
              this.uploadQueue.push({file : $file})
            }
          }
        }
      }
    },
    // 触发上传
    handleAdd(){
      this.$refs.inputFile.dispatchEvent(new MouseEvent('click'))
    },
    // 图片上传方法
    uploadFunc(index = 0){
      const upload = new Promise((resolve,reject) =>{
          if(!this.uploadQueue[index] || index > this.limit - 1) return
          // eslint-disable-next-line no-new
          // 图片上传方法
          uploadOSSFunc({
              fileData: [this.uploadQueue[index].file],
              fileSize: this.fileSize,
              onSuccess: (response) => {
                this.pictureCard.fileList.push({
                  name: data.file.name,
                  url: data.url,
                  thumbnail: `${response.url}?x-oss-process=image/resize,m_fixed,h_${this.thumbnailHeight},w_${this.thumbnailWidth}/sharpen,100`,
                  original : data.url
                })
              })
          })
      })
      upload.then(() => {
        if(this.uploadQueue.length - 1 === index){
          this.returnData()
          this.uploadQueue = []
          if(this.$refs.inputFile && this.$refs.inputFile.value) {
            this.$refs.inputFile.value = null
          }
        }
        this.uploadFunc(index + 1)
      })
    },
    // 删除图片
    handleRemove(file, index) {
      this.pictureCard.fileList.splice(index, 1)
      this.returnData()
    },
    // 图片超出限制
    handleExceed() {
      this.$message.error(`当前只允许上传 ${this.limit} 个文件`);
    },
    // 返回数据
    returnData(){
      const resArr = this.pictureCard.fileList.map(item => {
        return {
          url: item.original,
          original: item.original
        }
      })
      this.$emit('update:fileLists', resArr)
    }
  }
}
</script>

CSS部分:

<style scoped lang="scss" rel="stylesheet/scss">
.upload-wrap {
  padding: 0;
  overflow: hidden;
  background: #fff;
  .progress-wrap {
    margin-right: 10px;
    display: inline-block;
    vertical-align: top;
  }
  .upload-plus {
    vertical-align: top;
    display: inline-block;
    border: 1px dotted #d9d9d9;
    text-align: center;
    line-height: 100%;
    border-radius: 5px;
    cursor: pointer;
    background: #fbfdff;
    i.icon-add {
      font-size: 20px;
      color: #999;
    }
    .upload-wrap-input {
      display: none;
    }
  }
  .images-viewer {
    display: inline;
    vertical-align: top;
    .image-li {
      float: left;
      margin: 0 10px 10px 0;
      position: relative;
      i.icon-delete {
        position: absolute;
        top: 10px;
        right: 10px;
        color: #fd4e4d;
        font-size: 18px;
        cursor: pointer;
      }
      i.icon-delete-bg {
        position: absolute;
        top: 15px;
        right: 14px;
        font-size: 18px;
        width: 10px;
        height: 10px;
        background: #fff;
        border-radius: 10px;
      }
    }
    img {
      border-radius: 4px;
      border: 1px dotted #d9d9d9;
    }
  }
}
</style>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值