vue 拖动排序(拖动到指定位置)

105 阅读1分钟
<template>
  <div>
    <div class="col top" style="width: 100%">
      <draggable v-model="peo" :clone="cloneElement" animation="300" :options="{ group: { name: 'groupB', pull: 'clone' }, sort: true }">
        <transition-group>
          <div class="item" style="display: flex" v-for="item in peo" :key="item.id">{{ item.name }}</div>
        </transition-group>
      </draggable>
    </div>

    <!-- 使用draggable组件 -->
    <div class="clone-example">
      <div class="col" style="width: 200px">
        <draggable v-model="arr1" :clone="cloneElement" animation="300" :options="{ group: { name: 'groupB', pull: 'clone' }, sort: true }">
          <transition-group>
            <div class="item" v-for="item in arr1" :key="item.id">{{ item.name }}</div>
          </transition-group>
        </draggable>
      </div>
      <div class="col" v-for="(i, index) in 12" :style="{ width: '200px' }">
        <h4>{{ index + 1 }}</h4>
        <draggable v-model="arr2[i - 1]" :group="groupB" animation="300" @before-drop="validateDrop">
          <transition-group :style="style">
            <div class="item2" v-for="item in arr2[i - 1]" :key="item.id">{{ item.name }}</div>
          </transition-group>
        </draggable>
      </div>
    </div>
    <el-button @click="print">打印</el-button>
  </div>
</template>

<script>
// 导入draggable组件
import draggable from "vuedraggable";
export default {
  // 注册draggable组件
  components: {
    draggable,
  },
  data() {
    return {
      style: "min-height:120px;display: block",
      grpupPro: {
        // 可以拖出,禁止拖入
        name: "site",
        pull: true,
        put: false,
      },
      grpupA: {
        // 可以拖出,禁止拖入
        name: "site",
        pull: true,
        put: false,
      },
      groupB: {
        // 可以拖出,可以拖入
        name: "itxst",
        pull: true,
        put: true,
      },
      // 定义要被拖拽对象的数组
      arr1: [
        { id: 1, name: "www.itxst.com" },
        { id: 2, name: "www.jd.com" },
        { id: 3, name: "www.baidu.com" },
        { id: 4, name: "www.taobao.com" },
        { id: 5, name: "www.google.com" },
      ],
      peo: [
        { id: 6, name: "小布" },
        { id: 7, name: "小明" },
        { id: 8, name: "小看" },
        { id: 9, name: "小白" },
        { id: 10, name: "小红" },
      ],
      arr2: [[], [], [], [], [], [], [], [], [], [], [], []],
    };
  },
  methods: {
    // 克隆元素
    cloneElement(item) {
      return { ...item };
    },
    print() {
      console.log(this.arr2);
    },
    isDuplicateItem(targetArr, item) {
      return targetArr.some((arrItem) => arrItem.id === item.id);
    },

    validateDrop(event) {
      const targetArr = this.arr2[event.to.parentElement.dataset.idx - 1];
      const draggedItem = event.item;
      if (this.isDuplicateItem(targetArr, draggedItem)) {
        event.cancel = true; // 阻止拖动
      }
    },
  },
};
</script>

<style scoped>
.top {
  margin-bottom: 40px;
  display: flex;
}
.top .item {
  width: 120px;
  margin: 0 12px;
}
.top span {
  display: flex;
}
.clone-example {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.col {
  background-color: #f2f2f2;
  padding: 10px;
  border-radius: 5px;
  overflow-y: auto;
}

.item,
.item2 {
  margin-bottom: 10px;
  padding: 10px;
  background-color: #fff;
  border: 1px solid #ccc;
  border-radius: 5px;
  cursor: move;
}

.item2 {
  background-color: #f5f5f5;
}

.item:not(.ex-moved),
.item2:not(.ex-moved) {
  transition: transform 0.2s;
}

.item.ex-moved,
.item2.ex-moved {
  opacity: 0;
  height: 0;
  margin: 0;
  padding: 0;
}
</style>