vue drag函数拖拽效果实现

实现过程用到的函数介绍

  • 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)';
      }
    },

实现效果

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现小方块的拖拽效果,可以通过自定义指令来实现。以下是实现步骤: 1. 在指令中绑定拖拽元素的事件监听器,包括mousedown、mousemove和mouseup事件。 2. 在mousedown事件中记录鼠标按下时的位置和拖拽元素的初始位置。 3. 在mousemove事件中计算鼠标移动的距离,并将拖拽元素的位置进行相应的调整。 4. 在mouseup事件中清除事件监听器。 下面是一个实现小方块拖拽效果的自定义指令的示例代码: ```javascript // 注册自定义指令 Vue.directive('drag', { bind: function (el, binding, vnode) { // 记录拖拽元素的初始位置 var initX, initY, startX, startY; // 鼠标按下时的事件处理函数 function mouseDownHandler(e) { initX = el.offsetLeft; initY = el.offsetTop; startX = e.clientX; startY = e.clientY; // 添加事件监听器 document.addEventListener('mousemove', mouseMoveHandler); document.addEventListener('mouseup', mouseUpHandler); } // 鼠标移动时的事件处理函数 function mouseMoveHandler(e) { var deltaX = e.clientX - startX; var deltaY = e.clientY - startY; // 计算拖拽元素的新位置 var newX = initX + deltaX; var newY = initY + deltaY; // 设置拖拽元素的新位置 el.style.left = newX + 'px'; el.style.top = newY + 'px'; } // 鼠标松开时的事件处理函数 function mouseUpHandler() { // 移除事件监听器 document.removeEventListener('mousemove', mouseMoveHandler); document.removeEventListener('mouseup', mouseUpHandler); } // 添加鼠标按下事件监听器 el.addEventListener('mousedown', mouseDownHandler); } }); ``` 使用该指令时,只需要在需要实现拖拽效果的小方块元素上添加v-drag指令即可: ```html <div v-drag class="drag-box"></div> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值