SortTable实现el-table行拖拽
准备工作
安装:element UI
npm i element-ui -S
安装:sorttablejs
npm install sortablejs --save
我这里直接在html中的demo,模板样式如下:
<!--
el-table 行拖拽拖拽
1、同表单内拖拽位置
2、两个表单内互拖
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>行拖拽拖拽</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="../libs/sortTable/SortTable.min.js"></script>
<style>
.box {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.box1 {
height: 350px;
width: 45%;
float: left;
margin: 15px 5px;
border: 1px solid grey;
}
/* 修改el-table的显示区域 */
.el-table__body {
height: 350px;
width: 100%;
}
.el-table__empty-block {
display: none;
}
</style>
</head>
<body>
<div id="app" class="box">
<div class="box1">
<el-table class="tab1" :data="table1Data" border height="350" style="width: 100%">
<el-table-column prop="date" label="日期" width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" width="180">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
</el-table>
</div>
<div class="box1">
<el-table class="tab2" :data="table2Data" border height="350" style="width: 100%">
<el-table-column prop="date" label="日期" width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" width="180">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
</el-table>
</div>
</div>
<script>
new Vue({
el: "#app",
data() {
return {
table1Data: [{
pkid: "001",
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区泥沙江路 1518 弄'
}, {
pkid: "002",
date: '2016-05-04',
name: '张三',
address: '上海市普陀区金沙江路 1517 弄'
}, {
pkid: "003",
date: '2016-05-01',
name: '李四',
address: '上海市普陀区黄土江路 1519 弄'
}, {
pkid: "004",
date: '2016-05-03',
name: '王麻子',
address: '上海市普陀区水泥路 1516 弄'
}, {
pkid: "005",
date: '2016-05-08',
name: '赵四',
address: '上海市普陀区水泥路 1516 弄'
}],
table2Data: [],
};
},
});
</script>
</body>
</html>
单table表内拖拽
先实现当前table内实现拖动,查看官网,发现sorttablejs配置项中有很多情况的配置,我们就根据自己的需求来选取,我这里只是内部变动,我就找到一个事件:列表内元素顺序更新的时候触发onUpdate() {}, 当然onEnd(){}也能实现,可是看他的说明他是每种情况结束都会执行,我们待会还有其他的要求,就不使用它。
// 列表内元素顺序更新的时候触发
onUpdate: function (/**Event*/evt) {
// same properties as onEnd
},
在我们改变拖动的时候发现他会把html元素一并移动了,这个不是我们想要的,我们只关注数据列的改变,因为我们在实际使用中也许要使用改变后的数据去做一些事情,所以我们在onUpdate时就要处理数据。
onUpdate: function ({ newIndex, oldIndex }) {
// 相等不用管
if (newIndex == oldIndex) {
return;
}
// 拿到改变前的数据待会插入到新位置,删除原位置
let temp = list[oldIndex];
list.splice(oldIndex, 1);
list.splice(newIndex, 0, temp);
}
到这就查看一下就可以发现我们已经可以拖动了🤣🤣🤣
然而根据剧情的发展,不出意外的话,意外就要来了,不知你在拖动时是否发现问题:
拖动前:
记住该图片各个人物的名字位置不要眨眼,看好拖动后的情形:把王小虎拖动到第三行位置
意外来的总是很突然,这里就有一个关键:el-table :row-key(不会加的可以去阅读一下elementUI的table,row-key最好给他的值为主键这些唯一的)
也就是主键,确保他的唯一,加上之后就会发现,哇,成功了
刷新:把王小虎拖动到第三行位置,一切正常了
两个table互拖
第一个会了,第二不也一样手到擒来么,上边html也看到了我写了两个table。
继续查询sorttablejs配置项我们又发现了:元素从一个列表拖拽到另一个列表(onAdd)
// 元素从一个列表拖拽到另一个列表
onAdd: function (/**Event*/evt) {
// same properties as onEnd
},
编写了实现之后如下:
onAdd: function (evt) {
// evt中包含了原位置下标,新位置下标的信息,具体可以自己打印一看
// 添加目标数据
// oldObj另一张表中被拖动的元素
list.splice(evt.newIndex, 0, oldObj);
// 拿到被拖动的数组,然后删除被移走的元素
let sourceData = oldData;
sourceData.splice(evt.oldIndex, 1);
},
看到上边想法应该是很简单的就实现了,但是你会发现有些数据这里拿不到,这里不同于同表里移动它的传入的list数据都是同一个集合,这里的确是两个,而且打印发现我们从tab1拖到tab2,onAdd里边的list是tab2的,就意味着我们拿不到tab1的???
是这样吗?好像是的,但是有问题我们就解决问题,既然直接地解决方法没有,我们就用间接的,再次查询官方文档发现:
// 开始拖拽的时候
onStart: function (/**Event*/evt) {
evt.oldIndex; // element index within parent
},
开始拖拽触发事件,开始拖拽肯定就是tab1了,因此我们可以把它的记录存放
// 在开始拖动的时候我们记录下他拖拽的是哪个元素(className)
_this.dataTrans = elClass;
// 根据classname去获取各自的list
function getSourceData(elClass) {
// if () {} else if () {} ...这里可以好多好多
if (elClass == "tab1") {
return this.table1Data;
}
return this.table2Data;
}
// 开始拖拽的时候
onStart: function (/**Event*/evt) {
let oldElClass = _this.dataTrans;
if (oldElClass) {
let oldList = getSourceData(oldElClass);
let oldObj = oldList[evt.oldIndex];
// 添加目标数据
list.splice(evt.newIndex, 0, oldObj);
oldList.splice(evt.oldIndex, 1);
}
},
再次拖拽:
查看打印出来的结果:
最终顺序和每个table的值都对了。
有一个不足就是拖拽到空表时,需要放到表头下边那条线上才放的进去,本人前端不是很能,只能这样,有能力的可以帮忙修改。
附上完整源码:
需要导入的工具:elementUI,sorttablejs, vue,自己可以下载安装
<!--
el-table 行拖拽拖拽
1、同表单内拖拽位置
2、两个表单内互拖
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>行拖拽拖拽</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="../libs/sortTable/SortTable.min.js"></script>
<style>
.box {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.box1 {
height: 350px;
width: 45%;
float: left;
margin: 15px 5px;
border: 1px solid grey;
}
.el-table__empty-block {
display: none;
}
</style>
</head>
<body>
<div id="app" class="box">
<button type="button" @click="btnClick">Click</button>
<div class="box1">
<el-table class="tab1" :data="table1Data" row-key="pkid" border height="350" style="width: 100%">
<el-table-column prop="date" label="日期" width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" width="180">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
</el-table>
</div>
<div class="box1">
<el-table class="tab2" :data="table2Data" row-key="pkid" border height="350" style="width: 100%">
<el-table-column prop="date" label="日期" width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" width="180">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
</el-table>
</div>
</div>
<script>
new Vue({
el: "#app",
data() {
return {
table1Data: [{
pkid: "001",
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区泥沙江路 1518 弄'
}, {
pkid: "002",
date: '2016-05-04',
name: '张三',
address: '上海市普陀区金沙江路 1517 弄'
}, {
pkid: "003",
date: '2016-05-01',
name: '李四',
address: '上海市普陀区黄土江路 1519 弄'
}, {
pkid: "004",
date: '2016-05-03',
name: '王麻子',
address: '上海市普陀区水泥路 1516 弄'
}, {
pkid: "005",
date: '2016-05-08',
name: '赵四',
address: '上海市普陀区水泥路 1516 弄'
}],
table2Data: [],
dataTrans: null,
};
},
mounted() {
this.sortTableFun("tab1", this.table1Data);
this.sortTableFun("tab2", this.table2Data);
},
methods: {
sortTableFun(elClass, list) {
const _this = this;
const el = document.querySelector(`.${elClass} .el-table__body-wrapper tbody`);
Sortable.create(el, {
group: {
name: "tabGroup",
pull: true,
put: true
},
amimation: 180,
onStart: function (/**Event*/evt) {
_this.dataTrans = elClass;
},
onUpdate: function ({ newIndex, oldIndex }) {
// 相等不用管
if (newIndex == oldIndex) {
return;
}
let temp = list[oldIndex];
list.splice(oldIndex, 1);
list.splice(newIndex, 0, temp);
},
onAdd: function (evt) {
let oldElClass = _this.dataTrans;
if (oldElClass) {
let oldList = getSourceData(oldElClass);
let oldObj = oldList[evt.oldIndex];
// 添加目标数据
list.splice(evt.newIndex, 0, oldObj);
oldList.splice(evt.oldIndex, 1);
}
},
});
// 根据classname去获取各自的list
function getSourceData(elClass) {
// if () {} else if () {} ...这里可以好多好多
if (elClass == "tab1") {
return _this.table1Data;
}
return _this.table2Data;
}
},
btnClick() {
console.log({ tab1: this.table1Data, tab2: this.table2Data });
}
}
});
</script>
</body>
</html>