大家都知道element中的树形控件要想拖动排序,我们只需要设置其draggable属性即可,但是在表格中要如何实现该操作呢?element官网中并没有提到,但是我们可以基于一些第三方的插件实现,今天给大家分享一个功能强大的JavaScript拖拽库—SortableJS。
npm install sortablejs --save
cnpm install sortablejs --save
import Sortable from 'sortablejs'
el-table
中必须加上 row-key="id"
,否则可能会导致排序不成功。原因是因为 vue
的加载循环机制,在进行删除时,一定要添加 key
,跟使用 v-for
循环一样都需要添加绑定 key
值。
基础表格拖动排序
<template>
<div>
<!-- 表格控件 -->
<el-table :data="tableData" ref="tableNode" border highlight-current-row row-key="id">
<el-table-column prop="name" label="姓名" align="center"></el-table-column>
<el-table-column prop="sex" label="性别" align="center"></el-table-column>
<el-table-column prop="age" label="年龄" align="center"></el-table-column>
<el-table-column prop="address" label="地址" align="center"></el-table-column>
</el-table>
</div>
</template>
<script>
import Sortable from "sortablejs"; //引入下载的插件
export default {
data() {
return {
// 模拟数据
tableData: [
{
id: "1",
name: "第一",
sex: "男",
age: "12",
address: "北京",
},
{
id: "2",
name: "第二",
sex: "男",
age: "23",
address: "上海",
},
{
id: "3",
name: "第三",
sex: "女",
age: "21",
address: "广州",
},
{
id: "4",
name: "第四",
sex: "女",
age: "12",
address: "深圳",
},
],
};
},
mounted() {
this.pullSort(); //声明表格拖动排序方法
},
methods: {
//表格拖动排序方法
pullSort() {
// 通过ref获取Dom节点
const el = this.$refs.tableNode.$el.querySelectorAll(
".el-table__body-wrapper > table > tbody"
)[0];
this.sortable = Sortable.create(el, {
animation: 600, //拖拽动画(毫秒)
setData: function (dataTransfer) {
dataTransfer.setData("Text", "");
},
// 结束拖拽
onEnd: (e) => {
//e.oldIndex为拖动一行原来的位置;e.newIndex为拖动后新的位置
const oldRow = this.tableData[e.oldIndex]; // 移动元素集合
const newRow = this.tableData[e.newIndex]; // 新的元素集合
console.log(oldRow, "移动元素集合");
console.log(newRow, "新的元素集合");
// 调用接口传参即可
},
});
},
},
};
</script>
树形结构表格拖动排序
树形表格拖动不同于简单的表格拖动,我们要考虑到树形表格每一层的层级,如果返回的数据没有层级,我们需要给树形的数据去添加每一层的层级,其次,我们还得将树形表格数据转化为平铺数据在进行拖动,如果不转换的话,后面拖动的位置就是不对的,就会出错了,下面看代码实例。
<template>
<div>
<!-- 表格树控件 -->
<el-table :data="tableData" ref="tableNode" border highlight-current-row row-key="id">
<el-table-column prop="label" label="模块" align="center"></el-table-column>
</el-table>
</div>
</template>
<script>
import Sortable from "sortablejs"; //引入下载的插件
// import { treeSort } from "@/api/system";//引入接口方法
export default {
data() {
return {
// 模拟数据,实际情况根据后台返回数据调整
tableData: [
{
id: "2619",
label: "菜单一",
parentId: "79f32a6fdbaisdaishdadhsd0b3540e17a0a",
},
{
id: "4d1dd2a5wd3s2f1a5fd1as8f6869dc7b",
label: "菜单二",
parentId: "79f32a6fdbaisdaishdadhsd0b3540e17a0a",
children: [
{
id: "4006",
label: "A-1",
parentId: "4d1dd2a5wd3s2f1a5fd1as8f6869dc7b",
},
],
},
{
id: "52cqw8r7f4a65s3d1a5f4s65a3d2w1507f93",
label: "菜单三",
parentId: "79f32a6fdbaisdaishdadhsd0b3540e17a0a",
children: [
{
id: "4005",
label: "B-1",
parentId: "52cqw8r7f4a65s3d1a5f4s65a3d2w1507f93",
},
],
},
{
id: "66d5a4s13d2c1as5f4a6w5s13das12a89",
label: "菜单四",
parentId: "79f32a6fdbaisdaishdadhsd0b3540e17a0a",
children: [
{
id: "3033",
label: "C-1",
parentId: "66d5a4s13d2c1as5f4a6w5s13das12a89",
},
{
id: "3034",
label: "C-2",
parentId: "66d5a4s13d2c1as5f4a6w5s13das12a89",
},
],
},
],
activeRows: [], // 转换为列表的数据
};
},
mounted() {
this.pullSort(); //声明表格拖动排序方法
},
methods: {
//拖拽排序
pullSort() {
const tbody = this.$refs.tableNode.$el.querySelectorAll(".el-table__body-wrapper > table > tbody")[0];
const _this = this;//防止this指向问题
Sortable.create(tbody, {
animation: 600,
onMove({ dragged, related }) {
_this.$set(_this,"tableData",_this.arrayTreeSetLevel(_this.tableData)); // 树形结构数据添加level
_this.activeRows = _this.treeToTile(_this.tableData); // 把树形的结构转为列表再进行拖拽
},
onEnd(e) {
//e.oldIndex为拖动一行原来的位置,e.newIndex为拖动后新的位置
if (e.oldIndex !== e.newIndex) {
const oldRow = _this.activeRows[e.oldIndex]; // 移动元素
const newRow = _this.activeRows[e.newIndex]; // 新的元素
// level 当前层级 parentId 父级id
if (oldRow.level != newRow.level || oldRow.parentId != newRow.parentId) {
//不能跨级拖拽
_this.$message({
message: "只允许同级拖拽",
type: "warning",
});
_this.tableData = [];//清空列表数据
// _this.getTableTree();//调用列表接口
return false;
} else {
// // 接口参数
// let data = {
// previousId: oldRow.id,
// lastId: newRow.id,
// };
// // 请求接口
// treeSort(data).then((res) => {
// if (res.code == "10000") {
// _this.tableData = [];//清空列表数据
// _this.getTableTree();//调用列表接口
// _this.$message({
// message: res.msg,
// type: "success",
// });
// }
// });
}
}
},
});
},
// 给树形的数据去添加每一层的层级
arrayTreeSetLevel(array, levelName = "level", childrenName = "children") {
if (!Array.isArray(array)) {
return [];
}
const recursive = (array, level = 0) => {
level++;
return array.map((v) => {
v[levelName] = level;
const child = v[childrenName];
if (child && child.length) {
recursive(child, level);
}
return v;
});
};
return recursive(array);
},
// 将树数据转化为平铺数据
treeToTile(treeData, childKey = "children") {
const arr = [];
const expanded = (data) => {
if (data && data.length > 0) {
data
.filter((d) => d)
.forEach((e) => {
arr.push(e);
expanded(e[childKey] || []);
});
}
};
expanded(treeData);
return arr;
},
},
};
</script>
SortableJS
为开发者提供了多种拖动效果,单列表、多列表、嵌套排序等等都不在话下,大家感兴趣的话可以去官网查看: SortableJS 中文网
有关于 element 中树形控件(el-tree)如何实现拖动效果,大家可移步博主另一篇文章(vue基于element树形控件实现上下拖拽)