在 vue中使用 html5 的 drag和 drop 拖拽功能

本文介绍如何在Vue框架中实现不直接操作DOM的拖拽功能,通过数据操作来更新视图,保持数据状态的一致性,适用于表单字段的映射等场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

导读: 我们现在用的框架是vue,提倡的是尽量不操作dom,而 html5中的 drag 和 drop 是拖出当前选中元素,再放到设置了dragover的目标元素中,不符合vue的理念,而且操作dom改变目前布局也不利于我们去保存数据,所以就想到了个一个既不操作dom又能实现拖拽的功能。

一、回顾 html5 可拖拽 drag和drop

需要注意的是,需要被拖动的元素必须要设置 draggable=‘true’

  • drag:拖动元素,是将html元素从页面上拖起,它的事件如下:
    1. draggable:设置html 元素为可拖动元素,值为true
    2. ondragstart :当用户单击元素,并开始拖动时触发事件
    3. ondrag :拖动中触发事件
    4. ondragend :完成拖动后触发事件
  • drop:释放元素,是放拖动起来的元素进入到目标区域中的功能,事件如下:
    1. ondragenter :拖起来的元素进入到目标区域中时触发事件
    2. ondragover :拖动元素在目标区域中移动时触发事件
    3. ondragleave :当拖动元素离开目标区域时触发事件
    4. ondrop :拖动元素在目标区域中 释放鼠标时触发

给大家一个在js,或者jquery中操用通用demo:
在这里插入图片描述

.group{ display: flex; flex-direction: row; justify-content: space-around;width: 500px; height: 200px; }
.group>div{margin: 20px; border: 1px solid #333; width: 200px; cursor: pointer; }
.group>div p{ background: red;}
<div class="group">
   <div class="drag-block">
   <!-- 操作dom 时必须要有ID-->
     <p  id="drag" draggable="true" ondragstart="drag(event)" >我是可拖动元素</p>
   </div>
   <div  id="drop" ondrop="drop(event)" ondragover="dropOver(event)" class="drop-block"></div>
 </div>
function dropOver(e){
  e.preventDefault(); // 在拖动中阻止默认事件
}
function drag(e){
	// 开始拖动
    e.dataTransfer.setData("Text",e.target.id);
}

function drop(e){
  e.preventDefault();
  // 将拖动元素旋转到目标区域中
  var data=e.dataTransfer.getData("Text");
  e.target.appendChild(document.getElementById(data));
}
二、在vue中拖拽元素

接下来就是我们今天最重要的秀操作时间啦,哈哈哈 ~~~
我们要做的是 把 一张表 中的 基础字段和表单字段 映射到另一个表的 基础字段和表单字段中,字段分为多列和单列,在做映射的时候,单列只能映射单列,多列只能映射多列。
具体操作:

  1. 映射表中的数据 和 备选表中的数据分别放在两个 list 数组中
  2. 当拖动备选表中的数据时,将当前拖动的元素和位置放置(inde)到一个备用元素和备用位置(inde)中
  3. 当要释放备选表元素时,把备用元素根据备用位置中的下标放置在映射表的相应位置中,然后把备用表中的对应数据清除掉
  4. 当映射表中的数据相互拖动时,也是同样的道理 ,这样,我们就做到了只操作数据而不操作dom

上代码吧,代码只写了最主要的哈,字段的名称也改了,不能出卖公司的码子。。emmmmmm
在这里插入图片描述

<div class="shine-transfer">
<!-- 此处写查询功能 ,在这里就不给大家写了 -->
  <div class="shine-list">
    <ul>
      <li v-for="field in fieldList" :key="field.id">{{field.fieldzn}}<i v-show="field.isAllowMulti" class="el-icon-s-unfold"></i></li>
      <li v-for="annex in annexFieldList" :key="annex.id">{{annex.aFieldzn}}</li>
    </ul>
    <ul style="border-left: 1px solid #EBEEF5;">
      <li 
        v-for="(field, index) in infoList" 
        :key="index" 
        draggable="true" @dragstart="dragStart($event, index, field)" @dragover="allowDrop" @drop="drop($event, index,field)"
      >{{field.fieldzn}}</li>
    </ul>
  </div>
</div>

<div class="shine-transfer" style="margin-left: 20px">
  <!-- 此处写查询功能 ,在这里就不给大家写了 -->
  <div class="shine-list" @dragover="allowDrop" @drop="fileDrop($event)">
    <ul class="shine-ul">
      <li v-for="(ls,index) in relativeList" :key="index+'file'" draggable="true" @dragstart="fileDragStart($event, ls, index)" >
        {{ls.fieldzn}}
      </li>
    </ul>
  </div>
</div>
// 另一个表的拖动
dragStart(e, index, field){
    this.clearBakData() // 清空上一次拖动时保存的数据
    e.dataTransfer.setData('Text', index);
    this.fileMiddleData= field // 设置此次拖动时保存的数据
    this.fileMddleIndex = index //设置此次拖动时保存的数据Index
  }
 // 当前表的拖动
 fileDragStart(e, index,i){
   this.clearBakData() // 清空上一次拖动时保存的数据
   e.dataTransfer.setData('Text', index);
   this.middleData = index
   this.middleIndex = i
 }
 drop(e, index,field){
   // 取消默认行为
   this.allowDrop(e);
   // 判断拖起的元素是映射表中的数据,还是当前备选表中的数据
   if(JSON.stringify(this.middleData)!=='{}'){
   //  此处是映射表中的数据
   	// ... 此次写你们的逻辑
     this.clearBakData()
     
     // 放置到当前的数组中
     this.infoList.splice(index, 1, JSON.parse(JSON.stringify(this.middleData)))
     // 清除当前拖动的在另一个表中的数据
     if(this.middleIndex!==-1){
       this.relativeList.splice(this.middleIndex, 1)
     }
   }else{
   // 拖动的元素在当前张表时,交换两个数据的位置
      this.clearBakData()
     //使用一个新数组重新排序后赋给原变量
     let arr = this.infoList.concat([])
     let temp = arr[index];
     arr[index] = arr[this.fileMddleIndex];
     arr[this.fileMddleIndex] = temp;

     this.infoList = arr;
   }
   this.clearBakData()
 }
 // 从映射表中放到 备选表中
 fileDrop(e){
   //取消默认行为
   this.allowDrop(e);
    this.relativeList.push(this.fileMiddleData)
    this.infoList.splice(this.fileMddleIndex,1,JSON.parse(JSON.stringify(this.fileMiddleData))
   this.clearBakData()
 }
 allowDrop(e){
   e.preventDefault()
 }
 clearBakData(){
 	// 此处写清除各列表的操作
   this.middleData={}
   this.middleIndex=-1
   this.fileMiddleData={}
   this.fileMddleIndex=-1
 }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值