sortablejs el-table 树结构拖拽
最近要实现el-table的树状结构的列表拖拽功能
第一步:安装sortablejs
npm install sortablejs --save
第二步:在需要的页面引入
import Sortable from 'sortablejs'
第三步:表格样式布局
<el-table
:data="treeTableData"
ref="dragTable"
class="draggable"
row-key="id"
border
highligh-current-row
:expand-row-keys="treeTableExpandKeys"
@expand-change="treeTableExpandChange"
@selection-change="handleSelectionChange"
default-expand-all
>
<el-table-column type="selection" width="55" :selectable="selectableMethod" />
<el-table-column prop="date" label="Date" />
<el-table-column prop="name" label="Name" />
<el-table-column prop="address" label="Address" />
<el-table-column prop="handel" label="排序">
<template #default="{}">
<el-icon class="drag-hander" :size="20"><Rank /></el-icon>
</template>
</el-table-column>
</el-table>
第四步:数组定义
data() {
return {
treeTableData: [
{
id: 1,
date: '2016-05-02',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles',
},
{
id: 2,
date: '2016-05-04',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles',
},
{
id: 3,
date: '2016-05-01',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles',
children: [
{
id: 31,
date: '2016-05-06',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles',
children: [
{
id: 33,
date: '2016-05-08',
name: 'LIDAHAI',
address: 'No. 189, Grove St, Los Angeles',
},
{
id: 34,
date: '2016-05-09',
name: 'WANGJIUN',
address: 'No. 189, Grove St, Los Angeles',
},
],
},
{
id: 32,
date: '2016-05-07',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles',
},
],
},
{
id: 4,
date: '2016-05-03',
name: 'wangxiaohu',
address: 'No. 189, Grove St, Los Angeles',
},
],
treeProps: { checkStrictly: false, children: 'children', hasChildren: 'hasChildren' },
flatTreeData: [],
treeTableExpandKeys: [],
sortableObj: null,
};
},
第五步:初始化方法
mounted() {
this.transverseNode(this.treeTableData, 1, (node, level, parentNode) => {
node.level = level;
node.parentId = parentNode ? parentNode.id : -1;
});
this.initSortable();
this.getFlatNode(this.treeTableData, this.flatTreeData);
},
第六步:方法
methods: {
initSortable() {
const tbody = document.querySelector('.draggable .el-table__body-wrapper tbody');
if (!tbody) {
return;
}
Sortable.create(tbody, {
// Sortable 配置项
draggable: '.draggable .el-table__row',
onEnd: this.handleSortEnd, // 处理拖拽结束后的逻辑
});
},
handleSortEnd(event) {
if (event.oldIndex !== undefined && event.newIndex !== undefined) {
// const { oldIndex, newIndex } = event;
// const movedItem = this.tableData.splice(oldIndex, 1)[0];
// this.tableData.splice(newIndex, 0, movedItem);
const { newIndex, oldIndex } = event;
const dragRow = this.flatTreeData[oldIndex];
const relatedRow = this.flatTreeData[newIndex];
if (dragRow.parentId !== relatedRow.parentId) {
this.$message.warning('只能同层级内排序');
this.reRender(null, 'treeTableData');
} else {
// 都无children
if (!dragRow.children && !relatedRow.children) {
const oldData = this.flatTreeData.splice(oldIndex, 1)[0];
this.flatTreeData.splice(newIndex, 0, oldData);
}
// drag有, relate无
if (dragRow.children && !relatedRow.children) {
const oldData = this.flatTreeData.splice(oldIndex, 1)[0];
this.flatTreeData.splice(newIndex, 0, oldData);
if (newIndex < oldIndex) {
// 有子元素的,子元素需要同样跟上来
const flatChildren = [];
this.getFlatNode(oldData.children || [], flatChildren);
if (flatChildren.length > 0) {
for (let i = 1, len = flatChildren.length; i <= len; i++) {
const childData = this.flatTreeData.splice(oldIndex + i, 1)[0];
this.flatTreeData.splice(newIndex + i, 0, childData);
}
}
} else {
// 有子元素的,子元素需要同样跟下来
const flatChildren = [];
this.getFlatNode(oldData.children || [], flatChildren);
if (flatChildren.length > 0) {
for (let i = 1, len = flatChildren.length; i <= len; i++) {
const childData = this.flatTreeData.splice(oldIndex, 1)[0];
this.flatTreeData.splice(newIndex, 0, childData);
}
}
}
}
// drag无, relate有
if (!dragRow.children && relatedRow.children) {
const oldData = this.flatTreeData.splice(oldIndex, 1)[0];
this.flatTreeData.splice(newIndex, 0, oldData);
if (newIndex > oldIndex) {
// 有子元素的,子元素需要同样跟上来
const flatChildren = [];
this.getFlatNode(relatedRow.children || [], flatChildren);
if (flatChildren.length > 0) {
for (let i = 1, len = flatChildren.length; i <= len; i++) {
const childData = this.flatTreeData.splice(newIndex + i, 1)[0];
this.flatTreeData.splice(newIndex + i - 1, 0, childData);
}
}
}
}
// drag有, relate有
if (dragRow.children && relatedRow.children) {
if (newIndex < oldIndex) {
const oldData = this.flatTreeData.splice(oldIndex, 1)[0];
this.flatTreeData.splice(newIndex, 0, oldData);
// 有子元素的,子元素需要同样跟上来
const flatChildren = [];
this.getFlatNode(oldData.children || [], flatChildren);
if (flatChildren.length > 0) {
for (let i = 1, len = flatChildren.length; i <= len; i++) {
const childData = this.flatTreeData.splice(oldIndex + i, 1)[0];
this.flatTreeData.splice(newIndex + i, 0, childData);
}
}
} else {
const oldData = this.flatTreeData.splice(oldIndex, 1)[0];
// relateRow的children数
const relateFlatChildren = [];
this.getFlatNode(relatedRow.children || [], relateFlatChildren);
this.flatTreeData.splice(newIndex + relateFlatChildren.length, 0, oldData);
// 有子元素的,子元素需要同样跟下来
const flatChildren = [];
this.getFlatNode(oldData.children || [], flatChildren);
if (flatChildren.length > 0) {
for (let i = 1, len = flatChildren.length; i <= len; i++) {
const childData = this.flatTreeData.splice(oldIndex, 1)[0];
this.flatTreeData.splice(newIndex + relateFlatChildren.length, 0, childData);
}
}
}
}
// 重新生成树的数据
const data = this.getTreeData(this.flatTreeData, []);
console.log('this.flatTreeData', this.flatTreeData, data);
// 页面重新渲染
this.reRender(data, 'treeTableData');
}
}
},
getFlatNode(nodes, flatList, childrenKey = 'children') {
nodes.forEach(node => {
flatList.push(node);
if (node[childrenKey] && node[childrenKey].length) {
this.getFlatNode(node[childrenKey], flatList);
}
});
},
getTreeData(nodes, resultList) {
const childStack = [];
let lastNode = {};
nodes.forEach(node => {
delete node.children;
const pushNode = dataNode => {
const parentNode = childStack[childStack.length - 1];
if (parentNode) {
parentNode.children.push(dataNode);
} else {
resultList.push(dataNode);
}
};
if (node.level < lastNode.level) {
childStack.length = node.level - 1;
pushNode(node);
} else if (node.level === lastNode.level) {
pushNode(node);
} else if (node.level > lastNode.level) {
if (!lastNode.children) {
lastNode.children = [];
}
childStack.push(lastNode);
pushNode(node);
} else {
resultList.push(node);
}
lastNode = node;
});
return resultList;
},
reRender(data, dataKey) {
if (data) {
this[dataKey] = [];
this.$nextTick(() => {
this[dataKey] = data;
});
} else {
const origin = [].concat(this[dataKey]);
this[dataKey] = [];
this.$nextTick(() => {
this[dataKey] = origin;
});
}
},
transverseNode(nodes, level = 1, cb, parentNode, childKey = 'children') {
nodes.forEach(node => {
if (node[childKey] && node[childKey].length > 0) {
this.transverseNode(node[childKey], level + 1, cb, node, childKey);
}
cb(node, level, parentNode);
});
return nodes;
},
treeTableExpandChange(row, expanded) {
if (expanded) {
this.treeTableExpandKeys.push(row.id);
} else {
const idx = this.treeTableExpandKeys.indexOf(row.id);
this.treeTableExpandKeys.splice(idx, 1);
}
},
handleSelectionChange(selection){
console.log(selection); // 已选择的行数据数组
},
selectableMethod(row, index){
return row.id > 0 ? true:false;
}
},
第七步:移除
beforeDestroy() {
if (this.sortableObj) {
this.sortableObj.destroy();
}
},
参考链接:
https://blog.csdn.net/jianjian_19/article/details/120313084
https://www.jb51.net/javascript/31103517b.htm