导读: 我们现在用的框架是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 :拖动元素在目标区域中 释放鼠标时触发
给大家一个在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中拖拽元素
接下来就是我们今天最重要的秀操作时间啦,哈哈哈 ~~~
我们要做的是 把 一张表 中的 基础字段和表单字段 映射到另一个表的 基础字段和表单字段中,字段分为多列和单列,在做映射的时候,单列只能映射单列,多列只能映射多列。
具体操作:
- 映射表中的数据 和 备选表中的数据分别放在两个 list 数组中
- 当拖动备选表中的数据时,将当前拖动的元素和位置放置(inde)到一个备用元素和备用位置(inde)中
- 当要释放备选表元素时,把备用元素根据备用位置中的下标放置在映射表的相应位置中,然后把备用表中的对应数据清除掉
- 当映射表中的数据相互拖动时,也是同样的道理 ,这样,我们就做到了只操作数据而不操作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
}