el-upload 上传多张图片保证顺序 并支持拖拽

332 阅读1分钟

el-upload 上传多张图片保证顺序 并支持拖拽

<template>
  <div class="goods-upload_img_comp">
    <el-upload
      action="#"
      list-type="picture-card"
      :before-upload="beforeUpload"
      :limit="imgListLength"
      :http-request="KKHttpRequestImg"
      :file-list="imgList"
      drag
      accept=".png,.jpg,.jpeg"
      ref="uploadRef"
      :multiple="true"
      :class="[isShowUpload]"
      class="goods-upload_img-common"
    >
      <i class="goods-icon-plus"></i>
      <div slot="file" slot-scope="{ file }">
        <img
          class="goods-upload-list__item-thumbnail"
          style="width: 100px; height: 100px; cursor: pointer"
          :src="file.url"
          alt=""
          @click="handlePictureCardPreview(file)"
        />
        <img
          class="goods-upload-list-delete"
          src="@/assets/delete.png"
          alt=""
          @click.stop="clickDel(file)"
        />
      </div>
    </el-upload>
    <p class="goods-tip">
      单个图片大小不超过2M,支持png、jpg、jpeg,拖拽可调整顺序,快捷编辑的图片将优先在富文本框的内容上方展示
    </p>
    <el-image-viewer
      v-if="dialogVisible"
      class="image_viewer"
      :on-close="
        () => {
          dialogVisible = false
        }
      "
      :url-list="[dialogImageUrl]"
    />
  </div>
</template>
<script>
import { getDate, newMathNumber } from '@/utils/upload'
import ElImageViewer from 'element-ui/packages/image/src/image-viewer'
import { dragImg } from './dragTable.js'
import { deepClone } from '@/utils/index.js'export default {
  name: 'UploadImg',
  props: {
    // 限制图片大小 单位M
    imgSize: {
      type: Number,
      default: 2
    },
    // 限制图片数量
    imgListLength: {
      type: Number,
      default: 1
    },
    value: {
      default: '',
      type: []
    }
  },
  components: { ElImageViewer },
  data() {
    return {
      dialogImageUrl: '',
      disabled: false,
      dialogVisible: false,
      imgList: [],
      uploadQueue: [],
      isUpload: false
    }
  },
  watch: {
    value: {
      handler(nv) {
        this.imgList = deepClone(nv)
      },
      immediate: true
    }
  },
  computed: {
    isShowUpload() {
      if (this.imgList?.length >= this.imgListLength) {
        return 'goods-hiddenUpload'
      }
      return ''
    }
  },
  mounted() {
    this.$nextTick(() => {
      dragImg(this)
    })
  },
  methods: {
    // [AI-自定义上传方法操作]
    async promiseFun(params) {
      try {
        await this.$store.dispatch('ossclient/getStsToken')
        const file = params.file
        this.showFileName = file.name
        const dates = getDate()
        const mathNum = newMathNumber(4)
        // 生成文件名
        const stroeAs =
          'tempfile/template/pc/' +
          +dates +
          '/' +
          new Date().getTime() +
          '_' +
          mathNum +
          file.name.substring(file.name.lastIndexOf('.'))
        const result = await this.$store.getters.client.put(stroeAs, file)
        const imgProduct = {
          url: result.url,
          uid: file.uid
        }
        // 上传完成后重新初始化拖拽
        this.$message.success('上传成功')
        return imgProduct
      } catch (error) {
        console.log('???error', error)
      }
    },
​
    // [AI-队列上传]
    async processUploadQueue() {
      if (this.isUploading) return
      this.isUploading = true
      try {
        while (this.uploadQueue.length > 0) {
          const item = this.uploadQueue.shift() // 从队列头部取出并移除
          try {
            const res = await this.promiseFun(item)
            this.imgList.push(res)
            // 批量更新以减少触发次数
            this.$emit('input', [...this.imgList])
          } catch (error) {
            console.error('上传失败项:', item.file.name, error)
            // 可选:将失败项重新加入队列或进行其他处理
          }
        }
      } finally {
        this.isUploading = false
        // 检查是否有新项在处理过程中加入
        if (this.uploadQueue.length > 0) {
          this.processUploadQueue()
        }
      }
    },
​
    // [AI-添加任务到队列]
    async KKHttpRequestImg(params) {
      this.uploadQueue.push(params)
      this.$nextTick(() => this.processUploadQueue())
    },
​
    clickDel(file) {
      this.handleRemove(file)
      this.$message.success('已删除')
    },
    handleRemove(file) {
      this.imgList = this.imgList.filter(e => e.url !== file.url)
      this.$emit('input', this.imgList)
    },
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url
      this.dialogVisible = true
    },
​
    beforeUpload(file) {
      const isJPG =
        file.type === 'image/jpeg' ||
        file.type === 'image/png' ||
        file.type === 'image/jpg'
      const isLt2M = file.size / 1024 / 1024 < this.imgSize
      console.log('ceshi')
​
      if (!isJPG) {
        this.$message.error('上传图片只能是jpeg/jpg/png 格式!')
        return false
      } else if (!isLt2M) {
        this.$message.error(`上传图片大小不能超过 ${this.imgSize}MB!`)
        return false
      } else {
        return true
      }
    }
  }
}
</script>
<style scoped lang="scss">
.goods-upload_img_comp {
  padding: 0px 16px 16px 16px;
  ::v-deep {
    .goods-upload--picture-card,
    .goods-upload-dragger,
    .goods-upload-list__item {
      height: 100px;
      width: 100px;
      display: inline-block;
      line-height: 100px;
      margin-bottom: 0px;
    }
    // .goods-list-enter-to {
    //   display: none;
    // }
    .goods-hiddenUpload .goods-upload--picture-card {
      display: none;
    }
    .upload_msg {
      margin: 0;
      font-size: 14px;
      line-height: 14px;
      color: #999999;
    }
    .goods-upload-list__item.is-ready {
      display: none;
    }
    .goods-upload-list__item-status-label {
      display: none;
    }
    .goods-upload-list--picture-card {
      display: inline-block;
    }
  }
}
.goods-tip {
  font-weight: 400;
  font-size: 12px;
  color: #999;
  text-align: left;
  line-height: 20px;
  margin-top: 16px;
}
.goods-upload-list-delete {
  width: 16px;
  height: 16px;
  position: absolute;
  top: 2px;
  right: 2px;
  z-index: 9;
  cursor: pointer;
}
</style>

dragTable.js文件

import Sortable from 'sortablejs'export const dragImg = _this => {
  const dragElWrap =
    _this.$refs['uploadRef'].$el.querySelector('.goods-upload-list')
  console.log('dragElWrap', dragElWrap)
​
  Sortable.create(dragElWrap, {
    animation: 150,
    onEnd({ newIndex, oldIndex }) {
      _this.imgList.splice(newIndex, 0, _this.imgList.splice(oldIndex, 1)[0])
      _this.$emit('input', _this.imgList)
      // _this.imgList.forEach((item, index) => {
      //   item.sort = index
      // })
    }
  })
}
​