Vue 实现拖拽模块(一)拖拽添加组件

16 篇文章 0 订阅
7 篇文章 0 订阅

本文主要介绍了vue拖拽组件实现构建页面的简单实现,文中通过示例代码介绍,感兴趣的小伙伴们可以了解一下

本文主要介绍了 Vue拖拽添加组件的简单实现,具体如下:

效果图
在这里插入图片描述

实现思路

使用 H5 的新特性拖放操作来实现,拖拽左侧的组件放到右边主体部分,然后主体部分识别拖拽组件加载到盒子中 拖拽事件和属性

拖放操作的事件描述

事件名称事件描述
dragstart当单击下鼠标,并移动之后执行。
drag在dragstart执行之后,鼠标在移动时连续触发。
dragend当拖拽行为结束,也就是松开鼠标的时候触发。
dragenter当正在拖拽的元素的标记进入某个Dom元素时触发,自身首先会触发。被进入的Dom元素会触发这个事件。
dragover当拖拽的元素的标记在进入的Dom元素上移动时触发,在自身移动时也会触发。
dragleave当拖拽的元素在离开进入的Dom时触发。

H5拖拽属性 draggable

draggable:当需要某个元素可以拖拽时,需设置为true,默认为false。选中的文本、图片、链接默认可以拖拽。

DataTransfer对象:该属性用于保存拖放的数据和交互信息,通过 event 事件进行绑定属性和读取属性。
event.dataTransfer.getData(“绑定的属性名”);
event.dataTransfer.setData(“属性名”, “属性值”);

实现过程

  1. 给拖拽组件绑定 dragstart 事件用于监听拖拽开始
  2. 给拖拽组件添加 draggable=“true” 用于开启元素拖拽
  3. 给拖拽组件绑定 dragover.prevent 用于阻止浏览器默认行为, 不然会显示一个X,加上后在鼠标拖拽时会显示一个添加的小按钮
  4. 在 dragstart 触发的时候,需要把事件对象和当前数据传到方法中
  5. 把当前数据转换为字符串,并通过event.dataTransfer.setData() 方法,设置到 dataTransfer 对象中
  6. 给目标元素绑定 drop 事件,监听拖拽组件放到了当前元素中并使用event.dataTransfer.getData() 获取event对象上班绑定的拖拽元素的数据,保存到拖拽后的数组,然后把获取鼠标位置,将拖拽元素加载到鼠标放下的位置。
  7. 给拖拽元素绑定 dragover.prevent 用于阻止默认行为

完整代码

<template>
  <div class="box">
    <!-- 左侧拖拽组件 -->
    <div class="drap">
      <!-- 
            @dragstart  < -- 是元素开始拖拽的时候触发
            draggable="true"  < -- 为了使元素可拖动,把 draggable 属性设置为 true :
            @dragover.prevent < -- 阻止浏览器默认行为,不然会显示一个叉叉,不好看, 加上会显示一个添加的符号
         -->
      <div
        v-for="(item, index) in drapLeftElList"
        class="drap-item"
        :key="index"
        @dragstart="handleDrapEvList($event, item)"
        @dragover.prevent
        draggable="true"
      >
        <img
          class="drap-item-img"
          draggable="false"
          :src="item.imgUrl"
          :alt="item.name"
        />
        <div class="drap-item-name">{{ item.name }}</div>
      </div>
    </div>
    <!-- 主体部分 -->
    <div class="drap-container" @dragover.prevent @drop="handleDrap">
        <!-- @mousedown.stop="handleMouseDown($event, item, index)"
        @mouseup.stop="handleMouseUp" -->
      <div
        v-for="(item, index) in componentsList"
        class="drap-container-item"
        :key="index"
        :style="{ top: `${item.position.y}px`, left: `${item.position.x}px` }"
        @click="handleClick(item, index)"
      >
        <img class="drap-item-img" :src="item.imgUrl" :alt="item.name" />
        <div class="drap-item-name">{{ item.name }}</div>
      </div>
    </div>
    <!-- 属性配置 -->
    <div class="drap-right" style="width: 300px">
      属性配置
      {{ identifier }}
      {{ curControl }}
    </div>
  </div>
</template>

<script>
export default {
  name: "drap",
  data() {
    return {
      // 保存拖拽的元素的列表
      componentsList: [],
      //   元件库
      drapLeftElList: [
        {
          id: 11,
          name: "团队1",
          imgUrl:
            "http://img2.3png.com/68604d0c41a6cbc132055d03bbfade602ff7.png",
          sort: 1,
          position: {
            x: 0,
            y: 0,
          },
        },
        {
          id: 13,
          name: "团队2",
          imgUrl:
            "http://img2.3png.com/68604d0c41a6cbc132055d03bbfade602ff7.png",
          sort: 2,
          position: {
            x: 0,
            y: 0,
          },
        },
        {
          id: 14,
          name: "团队3",
          imgUrl:
            "http://img2.3png.com/68604d0c41a6cbc132055d03bbfade602ff7.png",
          sort: 3,
          position: {
            x: 0,
            y: 0,
          },
        },
        {
          id: 15,
          name: "团队4",
          imgUrl:
            "http://img2.3png.com/68604d0c41a6cbc132055d03bbfade602ff7.png",
          sort: 3,
          position: {
            x: 0,
            y: 0,
          },
        },
      ],
      identifier: "", // 当前项的 唯一标识
      curControl: null, // 当前点击的是哪个组件
    };
  },
  methods: {
    handleDrapEvList(event, value) {
      let { offsetX, offsetY } = event;
      var infoJson = JSON.stringify({
        ...value,
        position: {
          ...value.position,
          x: offsetX,
          y: offsetY,
        },
      });
      //   将数据绑定到dataTransfer身上
      event.dataTransfer.setData("drapData", infoJson);
    },
    // 监听拖拽元素结束
    handleDrap(event) {
      event.preventDefault();
      const value = event.dataTransfer.getData("drapData");
      //   获取绑定到拖拽元素身上的 drapData属性
      if (value) {
        let drapData = JSON.parse(value);
        // 获取指定鼠标在拖拽组件身上点击的位置
        
        const { position } = drapData;
        const identifier = Math.floor(Math.random() * 10000);
        // 获取当前鼠标拖拽结束的位置
        const {offsetX, offsetY} = event
        this.componentsList.push({
          ...drapData,
          identifier,
          position: {
            ...position,
 // 用鼠标拖拽结束的位置减去鼠标在元素上点击的位置, 就得到拖拽元素放置的当前位置
            x: offsetX - position.x,
            y: offsetY - position.y,
          },
        });
      }
    },
    // 点击元素获取组件配置
    handleClick(row, index) {
      this.identifier = row.identifier;
      this.curControl = row;
    },
  },
};
</script>

<style lang="scss">
.box {
  display: flex;
  flex-direction: row;
  align-items: center;
  height: 500px;
  overflow: hidden;
  .drap {
    width: 300px;
    height: 500px;
    background: #f2f2f2;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    cursor: pointer;
    .drap-item {
      height: 120px;
      margin-right: 20px;
      .drap-item-img {
        display: block;
        width: 80px;
        height: 80px;
      }
      .drap-item-name {
        text-align: center;
      }
    }
  }
  .drap-container {
    flex: 1;
    height: 500px;
    background: #ccc;
    position: relative;
    .drap-container-item {
      -webkit-user-select: none;
      -moz-user-select: none;
      -o-user-select: none;
      user-select: none;
      position: absolute;
      user-select: none;
      .drap-item-img {
        display: block;
        width: 80px;
        height: 80px;
      }
      .drap-item-name {
        text-align: center;
      }
    }
  }
}
</style>

总结

以上就是今天要分享的内容,本文简单介绍了 拖拽组件的拖拽功能和目标元素的识别并加载到指定位置

接下来我们会逐步去实现针对拖拽组件的设置位置、设置样式、设置属性、绑定事件等操作

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值