可拖拽 drag和drop

108 阅读2分钟

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

一、回顾 html5 可拖拽 drag和drop


需要注意的是,需要被拖动的元素必须要设置 draggable=‘true’
drag:拖动元素,是将html元素从页面上拖起,它的事件如下:
draggable:设置html 元素为可拖动元素,值为true
ondragstart :当用户单击元素,并开始拖动时触发事件
ondrag :拖动中触发事件
ondragend :完成拖动后触发事件
drop:释放元素,是放拖动起来的元素进入到目标区域中的功能,事件如下:
ondragenter :拖起来的元素进入到目标区域中时触发事件
ondragover :拖动元素在目标区域中移动时触发事件
ondragleave :当拖动元素离开目标区域时触发事件
ondrop :拖动元素在目标区域中 释放鼠标时触发
<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中拖拽元素

<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
 }