场景:
如果后台返回的树数据排序是按照其中的某一个属性来排序的,这里以number举例,如下图所示
那么移动的时候就要更新他的number值,以及原本数据位置
上下移动
(vue3+elementplus) tip:allMenu为菜单数据且为对象数组(非嵌套)即上图所示 currentNode(选中节点)和currentMenu(选中菜单)为业务需要,不需要可删除
updateNumber(data,oldStr,newStr){//data为某一项数据多维数组
function startsWith(str, prefix) {
return str.indexOf(prefix) === 0;
}
// Base case: if data is null or undefined, return immediately
if (!data) return;
// Check if the current node's number starts with oldStr
if (data.number && startsWith(data.number.toString(), oldStr)) {
// Update the number by replacing the oldStr prefix with newStr
data.number = newStr + data.number.toString().slice(oldStr.length);
}
// Recursively process the children
if (data.children && data.children.length > 0) {
data.children=data.children.map(child => {
this.updateNumber(child, oldStr, newStr);
return child;
});
}
},
updateallMenuNumber(data,oldStr,newStr){//data为全部数据一维数组
function startsWith(str, prefix) {
return str.toString().startsWith(prefix);
}
const matchedOld = data.filter(item => item.number.startsWith(oldStr));
const matchedNew = data.filter(item => item.number.startsWith(newStr));
const indexOld = data.findIndex(item => item.number.startsWith(oldStr));
const indexNew = data.findIndex(item => item.number.startsWith(newStr));
if (indexOld !== -1 && indexNew !== -1) {
let firstArr=data.slice(0,Math.min(indexOld,indexNew))
let endArr=[]
if(indexNew>indexOld){//上移
endArr=data.slice((indexNew+matchedNew.length),data.length)
data=firstArr.concat(matchedNew)
data=data.concat(matchedOld)
data=data.concat(endArr)
}else if(indexNew<indexOld){//下移
endArr=data.slice((indexOld+matchedOld.length),data.length)
data=firstArr.concat(matchedOld)
data=data.concat(matchedNew)
data=data.concat(endArr)
}
}
return data.map(item => {
if (item.number !== undefined) {
let newNumber;
if (startsWith(item.number.toString(), oldStr)) {
newNumber = newStr + item.number.toString().slice(oldStr.length);
item.number=newNumber
} else if (startsWith(item.number.toString(), newStr)) {
newNumber = oldStr + item.number.toString().slice(newStr.length);
item.number=newNumber
} else {
newNumber = item.number;
}
}
return item;
});
},
upMenu(){//上移菜单
const parent = this.$refs.tree.getNode(this.$refs.tree.getCurrentKey()).parent;
const children = parent.data.children || parent.data;
const cIndex = children.findIndex(d => d.menuId === this.currentMenu.menuId);
if (parent.level === 0 && cIndex === 0) {
return;
}
else if (
(parent.level === 0 && cIndex !== 0) ||
(parent.level !== 0 && cIndex !== 0)
) {
const tempChildrenNodex1 = JSON.parse(JSON.stringify(children[cIndex - 1]));
const tempChildrenNodex2 = JSON.parse(JSON.stringify(children[cIndex]));
children[cIndex]=tempChildrenNodex1
children[cIndex-1]=tempChildrenNodex2
let num1=JSON.parse(JSON.stringify(children[cIndex-1].number))
let num=JSON.parse(JSON.stringify(children[cIndex].number))
this.updateNumber(children[cIndex],num,num1)
this.updateNumber(children[cIndex-1],num1,num)
this.allMenu=this.updateallMenuNumber(this.flattenTree(this.data),num,num1)
this.currentNode=this.$refs.tree.getNode(this.$refs.tree.getCurrentKey())
this.currentMenu=this.$refs.tree.getCurrentNode()
this.$nextTick(()=>{ //此处为控制上下移动按钮是否可用
if (cIndex-1 === 0) {
this.upDisabled=true
this.downDisabled=false
}else if(cIndex-1<children.length-1){
this.upDisabled=false
this.downDisabled=false
}
//高亮行控制
if(this.$refs.tree)this.$refs.tree.setCurrentKey(children[cIndex-1].menuId)
})
}
},
downMenu(){//下移菜单
const parent = this.$refs.tree.getNode(this.$refs.tree.getCurrentKey()).parent;
const children = parent.data.children || parent.data;
const cIndex = children.findIndex(d => d.menuId === this.currentMenu.menuId);
if (parent.level === 0 && cIndex === children.length-1) {
return;
}
else if (
(parent.level === 0 && cIndex !== children.length-1) ||
(parent.level !== 0 && cIndex !== children.length-1)
) {
const tempChildrenNodex1 = JSON.parse(JSON.stringify(children[cIndex + 1]));
const tempChildrenNodex2 = JSON.parse(JSON.stringify(children[cIndex]));
children[cIndex]=tempChildrenNodex1
children[cIndex+1]=tempChildrenNodex2
let num1=JSON.parse(JSON.stringify(children[cIndex+1].number))
let num=JSON.parse(JSON.stringify(children[cIndex].number))
this.updateNumber(children[cIndex],num,num1)
this.updateNumber(children[cIndex+1],num1,num)
this.allMenu=this.updateallMenuNumber(this.flattenTree(this.data),num,num1)
this.currentNode=this.$refs.tree.getNode(this.$refs.tree.getCurrentKey())
this.currentMenu=this.$refs.tree.getCurrentNode()
this.$nextTick(()=>{
if (cIndex+1 === children.length-1) {
this.downDisabled=true
this.upDisabled=false
}else if(cIndex+1>0){
this.upDisabled=false
this.downDisabled=false
}
if(this.$refs.tree)this.$refs.tree.setCurrentKey(children[cIndex+1].menuId)
})
}
},
非特殊情况可参考elementPlus的Api Tree 树形控件 | Element Plus 其中的remove与insertBefore或insertAfter相互搭配进行上下移动
思路:记录原节点,remove删除原节点,将记录的节点通过insertBefore或insertAfter插入树中达到效果
合起与展开
el-tree 设置属性
:default-expanded-keys="expandedRightData"
:key="treeKey"
:default-expand-all="isExpand"
rowOpenORFold(isExpand) {// 展开或折叠全部的方法
this.treeKey = +new Date()
this.isExpand = isExpand
if(!this.isExpand) this.expandedRightData=[]
this.$nextTick(()=>{
this.rightTreeLoading=false
})
},
通过调用rowOpenORFold(是否展开:true||false)来控制该树项的展开与合起
感谢阅读