vue elementui+sortable.js嵌套表格拖拽
首先说下项目需求,一个多层嵌套的表格,行可以进行拖拽排序,但不能跨主级去拖拽,下拉可以异步获取数据,考虑了很久,还是用最熟悉的vue+element来做,但是element没有拖拽排序的功能,所以在此基础上加入sortable.js去实现拖拽功能。
后台返回的排序规则是 每个数据都带有3个属性 id next prev
用这3个属性实时的去更新排序
- id表示这一条数据的id
- next表示下一条数据的id
- prev表示上一条数据的id
html部分

data部分
flattarray:[], originaldata:[], tabledata: [], arr:[], maps:new map()
我这里定义了四个数组和一个map
flattarray是平铺的数据 originaldata数组也是平铺的数据(以防数据出错,没有啥实际用途) tabledata是表格渲染的数据 arr是点击下拉异步请求的数据
maps是tabledata改变后去重新渲染数据用的
methods部分
首先我定义了一个方法去深拷贝,这样改变一个数据的时候,其他数据不会改变
//深拷贝
getnewobject(val) {
let resobj = json.stringify(val);
return json.parse(resobj);
},加载页面从接口 获取 tabledata数据 并深拷贝 tabledata
getdetails(id){
axios.get(url).then(res =>{
if(res.data.code === 0){
this.tabledata = res.data.data
this.tabledata.map( item =>{
item.haschildren = true
delete item.children
})
this.flattarray = this.getnewobject(this.tabledata)
this.originaldata = this.getnewobject(this.tabledata)
}else{
this.$message.error('网络错误');
}
}).catch(function (error) {
this.$message.error('网络错误');
});
},这里表格就已经渲染出来了 ,因为下拉的数据要异步去获取,所以在element提供的下拉事件里面去请求数据,这里去获取子级的数据,并给maps赋值,利用递归,把数据平铺、组装。
//点击下拉图标异步加载数据
load(tree, treenode, resolve) {
this.maps.set(tree.id, { tree, treenode, resolve })
axios.get(`url` + tree.id).then(res => {
if (res.data.code == 0) {
this.arr = res.data.data
this.arr.map(item => {
item.haschildren = true
delete item.children
this.flattarray.push(item)
})
resolve(this.arr)
const tree = buildtree(this.flattarray, 1);
//组装tree
function buildtree(nodes, parent) {
const res = [];
for (let item of nodes) {
if (item.parentid === parent) {
const children = buildtree(nodes, item.id);
if (children.length) {
item.children = children;
}
res.push(item);
}
}
return res;
}
//平铺tree
let result = [];
function flattree(nodes, parentid) {
if (!nodes || nodes.length === 0) return [];
nodes.foreach(node => {
result.push(node);
return flattree(node.children, node.id);
});
}
flattree(tree, 1);
this.originaldata = result
this.getnewobject(this.originaldata)
} else {
this.$message.error('没有更多消息了');
}
})
},定义的行拖拽方法,因为排序是用的3个属性去排序的,所以有3种情况去考虑
- 一是拖动到最上级,这样prev的值就为空
- 二是拖动到最下级,next为空
- 三是正常的拖动,next prev都不为空
rowdrop() {
this.$nexttick(() => {
const tbody = document.queryselector('.el-table__body-wrapper tbody')
const _this = this
sortable.create(tbody, {
animation: 300,
sort: true,
onend({
oldindex,
newindex,
item
}) {
const sourceobj = _this.originaldata[oldindex - 1] // 原本的位置
const targetobj = _this.originaldata[newindex - 1] // 移动到的位置
const frontobj = _this.originaldata[newindex - 2] //移动后位置的上一级
const behindobj = _this.originaldata[newindex] //移动后位置的下一级
if(sourceobj.parentid != targetobj.parentid) {
_this.$message.error("不支持跨级拖动,请拖回原来位置")
location.reload();
return;
}
let data = [];
if( oldindex < newindex ){//向下移动
//上一级
let predata = {
id: targetobj.id,
next: sourceobj.id,
prev: targetobj.prev
}
//自己
let curdata = {
id: sourceobj.id,
next: targetobj.next,
prev: targetobj.id,
groupid: sourceobj.groupid
}
//下一级
let nextdata = null
if (behindobj != undefined && sourceobj.parentid == behindobj.parentid) {
nextdata = {
id: behindobj.id,
next: behindobj.next,
prev: sourceobj.id
}
}
if(nextdata){
data.push(curdata, predata, nextdata)
}else{
data.push(curdata, predata)
}
_this.postdata(data, sourceobj.parentid)
}else if( oldindex > newindex ){//向上移动
//上一级
let predata = null
if (frontobj != undefined && sourceobj.parentid == frontobj.parentid) {
predata = {
id: frontobj.id,
next: sourceobj.id,
prev: frontobj.prev
}
}
//自己
let curdata = {
id: sourceobj.id,
next: targetobj.id,
prev: targetobj.prev,
groupid: sourceobj.groupid
}
//下一级
let nextdata = {
id: targetobj.id,
next: targetobj.next,
prev: sourceobj.id
}
if(predata){
data.push(curdata, predata, nextdata)
}else{
data.push(curdata, nextdata)
}
_this.postdata(data, sourceobj.parentid)
}
}
})
})
},mounted 里面去加载 改变行的方法
mounted() {
this.rowdrop()
},最后再去动态的更新数据
refreshloadtree(parentid) {
// 根据父级id取出对应节点数据
const {tree, treenode, resolve} = this.maps.get(parentid)
this.$set(this.$refs.tabledata.store.states.lazytreenodemap, parentid, [])
if (tree) {
this.load(tree, treenode, resolve)
}
},到这里需求已经实现了,就没有去深入的挖掘,可能会有问题,但是隔的时间太久了,基本忘光了。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论