实现过程用到的函数介绍

  • dragstart:用户开始拖动元素时触发
  • dragenter: 当被鼠标拖动的对象进入其容器范围内时触发此事件
  • dragover:当某被拖动的对象在另一对象容器范围内拖动时触发此事件
  • dragend:用户完成元素拖动后触发
    其他具体函数可以看菜鸟教程的详细介绍

初步实现参考

<template>
  <ul class="list">
    <li
      @dragenter="dragenter($event, index)"
      @dragover="dragover($event, index)"
      @dragstart="dragstart(index)"
      draggable
      v-for="(item, index) in list"
      :key="item.label"
      class="list-item"
     >
      {{item.label}}
    </li>
  </ul>
</template>
<script>
export default {
  data() {
    return {
      list: [
        { label: '列表1' },
        { label: '列表2' },
        { label: '列表3' },
        { label: '列表4' },
        { label: '列表5' },
        { label: '列表6' },
      ],
      dragIndex: '',
      enterIndex: '',
    };
  },
  methods: {
    dragstart(index) {
      this.dragIndex = index;
    },
    dragenter(e, index) {
      e.preventDefault();
      // 避免源对象触发自身的dragenter事件
      if (this.dragIndex !== index) {
        const source = this.list[this.dragIndex];
        this.list.splice(this.dragIndex, 1);
        this.list.splice(index, 0, source);
        // 排序变化后目标对象的索引变成源对象的索引
        this.dragIndex = index;
      }
    },
    dragover(e, index) {
      e.preventDefault();
    },
  },
};
</script>
<style lang="scss" scoped>
.list {
  list-style: none;
  .list-item {
    cursor: move;
    width: 300px;
    background: #EA6E59;
    border-radius: 4px;
    color: #FFF;
    margin-bottom: 6px;
    height: 50px;
    line-height: 50px;
    text-align: center;
  }
}
</style>

作者:文小雄
链接:https://juejin.cn/post/6909287804510371847
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

更新实现思路

因为我需要实现的效果有以下几点不同:

  1. 拖动子模块间有关联关系,需要判定是否可拖动至另一位置
  2. 两层for循环嵌套,需要拖动的为里面一层for循坏嵌套div,不可从一个外层模块拖动至另一外层模块
  3. 触发拖动函数的仅一个icon

因此做了以下几点更新:

  1. 定义了一个全局变量判定是否可以继续拖动(因为每次触发dragenter是进入到一个新的子模块
  2. 添加一个全局变量判定当前进入到的外层模块是否为开始移动时的父级模块
  3. 将draggable=“true”属性放到icon上,再在每次拖动时给予整个子模块一个背景颜色加深的效果以达到拖动整个模块的视觉效果

具体实现代码

html:

	<div :ref="'box'+boxIndex" v-for="(itemBox, boxIndex) in tabList" :key="itemBox.id" class="content">
        <div class="title">{{itemBox.name}}</div>
        <div class="item-box">
          <div
            v-for="(item, index) in itemBox.config"
            :key="index"
            class="item"
            :ref="'item'+boxIndex+index"
            >
            <div class="left">
              <div class="index-number">{{index+1}}</div>
              <div class="model-name">{{item.tpl_name}}</div>
            </div>
            <div class="right">
              <div
                class="drag"
                draggable="true"
                @dragstart="dragstart(index, itemBox)"
                @dragenter="dragenter($event, index, itemBox)"
                @dragover="dragover($event)"
                @dragend="dragend(itemBox)"
                >
                <i class="icon-Move"/>
              </div>
            </div>
          </div>
        </div>
      </div>

js:

    dragstart(index, itemBox) {
      this.dragIndex = index;// 记录开始移动坐标
      this.startItem = itemBox;// 记录移动的外层模块
      this.dragFlag = true;// 判定是否可以继续移动
      const i = this.tabList.indexOf(itemBox);
      // 将移动的整个子模块背景颜色变深,致使呈现整个拖动的效果,也可以不要
      this.$refs['item' + i + index][0].style.background = 'rgb(215 237 255)';
    },
    dragenter(e, index, itemBox) {
      e.preventDefault();// 避免源对象触发自身的dragenter事件
      const i = this.tabList.indexOf(itemBox);// 用于判定当前进入的外层模块是否为一开始移动的外层模块
      const list = this.tabList[i].config;// 拖动的子模块列表list
      if (i === this.tabList.indexOf(this.startItem) && this.dragIndex !== index) {
      // 将所有子模块背景颜色还原
        for (let j = 0; j < list.length; j++) {
          this.$refs['item' + i + j][0].style.background = 'rgb(244 250 255)';
        }
      // 将移动到的当前位置模块颜色变深
        this.$refs['item' + i + index][0].style.background = 'rgb(215 237 255)';
      // 这里的判定逻辑是若是移动到了没有权限模块之前则不能继续移动,向下则是可以随意移动未作判定
        if (this.dragIndex && this.dragIndex > index && list[index].action_flag === 0) {
          this.dragFlag = false;
          this.$message.warning('不可移动到无权限模板之前');
        }
        // 判定是否可移动
        if (this.dragFlag === true) {
          const moving = list[this.dragIndex];
          list.splice(this.dragIndex, 1);
          list.splice(index, 0, moving);
          // 排序变化后目标对象的索引变成源对象的索引
          this.tabList[i].config = list;
        }
        this.dragIndex = index;
      }
    },
    dragover(e) {
      e.preventDefault();
    },
    dragend(itemBox) {
    // 将当前移动子模块颜色还原
      const i = this.tabList.indexOf(itemBox);
      if (this.$refs['item' + i + this.dragIndex][0]) {
        this.$refs['item' + i + this.dragIndex][0].style.background = 'rgb(244 250 255)';
      }
    },

实现效果

在这里插入图片描述
在这里插入图片描述
代码肯定还是不够完善,有问题还请大佬指正。

Logo

前往低代码交流专区

更多推荐