elementui 拖拽图片组件的实现

1,270 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

需求:

后台管理实现一个图片列表,图片可以拖拽实现位置更改

思路:

图片列表的渲染和上传组件、拖拽组件的组合

代码:

<template>
  <div class="more-img-uploade">
    <draggable
      :list="imgList"
      tag="ul"
      class="img-list"
      v-bind="dragOptions"
      draggable=".item"
    >
      <li v-for="(item, index) in imgList" :key="index" class="item">
        <img :src="item.url" alt="">
        <i
          v-if="!canEdit"
          class="el-icon-circle-close"
          @click="deletImgList(index)"
        />
      </li>
      //图片上传到限制张数时隐藏上传图标
      <li v-show="imgList.length < imgLimit" class="img-li">
        <el-upload
          :action="actionUrl"
          :headers="headers"
          :on-success="uploadSuccess"
          :before-upload="uploadBefore"
          class="upload-class"
          :show-file-list="false"
          :disabled="canEdit"
        >
          <i class="el-icon-plus" />
        </el-upload>
      </li>
    </draggable>
  </div>
</template>

import draggable from 'vuedraggable'
export default {
  components: {
    draggable
  },
  props: {
  //上传api
    actionUrl: {
      type: String,
      default: ''
    },
    //图片列表
    imgList: {
      type: Array,
      default() {
        return []
      }
    },
    //是否可编辑
    canEdit: {
      type: Boolean,
      default: false
    },
    //上传图片限制张数
    imgLimit: {
      type: Number,
      default: 0
    }
  },

  data() {
    return {
      headers: {
        'api-ver': '1.0.0',
        token: sessionStorage.token,
        charset: 'UTF-8'
      }
    }
  },
  computed: {
    // 拖拽属性
    dragOptions() {
      return {
        animation: 200, // 动画时间
        disabled: this.canEdit, // false可拖拽,true不可拖拽
        group: 'description',
        ghostClass: 'ghost'
      }
    }
  },
  methods: {
      //上传图片进行校验
    uploadBefore(file) {
      // 图片格式是否正确
      let bool = null
      // 获取图片的后缀名
      const dotIndex = file.name.lastIndexOf('.')
      const suffixOfImage = file.name.slice(dotIndex + 1).toLowerCase()
      switch (suffixOfImage) {
        case 'gif':
        case 'jpeg':
        case 'png':
        case 'jpg':
        case 'bmp':
        case 'tiff':
        case 'webp':
          bool = true
          break
        default:
          bool = false
      }
      if (bool) {
        const isLt5Mb = file.size / 1024 < 500
        if (isLt5Mb) return true
        else {
          this.$message.warning('上传图片大小不能超过 500kb!')
          return false
        }
      } else {
        this.$message.warning('您上传的图片格式不正确!')
        return false
      }
    },
    // 上传成功
    uploadSuccess(res, file, fileList) {
      this.hide = true
      if (res.code === 200) {
        if (res.data) this.imgList.push({ url: res.data[0] })
        if (res.response) this.imgList.push({ url: res.response[0] })
      } else {
        this.$message.warning(res.message)
      }
    },
    // 删除图片
    deletImgList(index) {
      this.imgList.splice(index, 1)
    }
  }
}
</script>

<style lang="scss">
.more-img-uploade .el-icon-circle-close {
  color: red;
  position: absolute;
  font-size: 15px;
  z-index: 999;
  right: 5px;
  top: 5px;
}
</style>
<style scoped>
.img-list {
  display: flex;
  flex-wrap: wrap;
  max-height: 350px;
  overflow-y: scroll;
}
.img-list .item:nth-child(1)::after {
  content: "首图";
  position: absolute;
  width: 40px;
  height: 20px;
  text-align: center;
  line-height: 20px;
  top: 0;
  left: 0;
  color: #ffffff;
  font-size: 14px;
  background: coral;
}
.img-list li,
.img-li {
  width: 180px;
  height: 120px;
  margin: 15px 10px;
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.img-li {
  float: left;
}
.img-list li img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}
.upload-class {
  font-size: 28px;
  color: #8c939d;
  text-align: center;
  height: 120px;
  width: 180px;
  line-height: 120px;
  box-sizing: border-box;
}
</style>

vuedraggable props:

value

类型:数组,
必需:否,
默认值:null

通常与内部元素v-for指令引用的数组相同,该组件的首先使用方法,与vuex兼容,也可使用v-model

list

类型:数组,
必需:否,
默认值:null

除了上面的 value prop之外,list是一个要与拖放同步的数组。
主要的区别是list prop是由使用splice方法的draggable组件更新的,而value是不可变的,两者不能一起使用
tag
类型:字符串
默认值:div

可拖动组件创建的元素的HTML节点类型,作为包含插槽的外部元素
还可以将vue组件的名称作为元素传递。在本例中,draggable属性将传递给创建的组件
clone
类型:function
默认值:(original) => { return original;}


当克隆选项为真时,调用源组件上的函数来克隆元素。
惟一的参数是要克隆的viewModel元素,返回的值是它的克隆版本。
在默认情况下vue.draggable重用viewModel元素,所以如果您想克隆或深度克隆它,就必须使用这个钩子。

引用时:

<GlobalUploadMoreImg
:can-edit="canEdit"
:action-url="actionUrl"
:img-list.sync="imgList"
:img-limit="9"
/>