在實際工做中,樹形數據很常見,例如vue中的路由數據,系統菜單也是樹形數據,組織管理也是樹狀的,DOM解構也是如此。例若有以下數據結構:vue
let tree = [
{
id:0,
name:'江西',
children:[
{ id:'01',name:'南昌',children:[]},
{ id:'02',name:'九江',children:[]}
]
},{
id:1,
name:'湖南',
children:[
{ id:'11',name:'長沙',children:[]},
{ id:'12',name:'衡陽',children:[]},
{ id:'13',name:'常德',children:[]},
]
}
]
複製代碼
在理論上講這種結構能夠無限延伸。每一個節點下可能有children,children下可能還有children. 下面列舉幾種對上述結構操做的經常使用方法僅供參考:
(如下代碼都是假如屬性都是經過children字段進行拓展的,每一個對象惟一標識爲id字段。)node
function flatTree(data) {
let result = []
for(let i = 0; i<data.length;i++){
let obj = {
id:data[i].id,
name:data[i].name
}
result.push(obj)
if (data[i]['children'] && data[i]['children'].length) {
result = result.concat(flatTree(data[i]['children']))
}
}
return result
}
// [{id:0,name:'江西'},{id:'01',name:'南昌'}...]
複製代碼
function findNode(data,id) {
let result = []
for(let i = 0; i<data.length;i++){
if (data[i].id === id) {
result.push(data[i])
}
if (data[i]['children'] && data[i]['children'].length) {
result = result.concat(findNode(data[i]['children'],id))
}
}
return result
}
複製代碼
經過查找某個id將返回一個數組結構,若是有id重複的,會返回全部重複的id對象數組數組
// 刪除樹操做
function deleteNode(data,id) {
for (let i =0;i<data.length;i++) {
if(data[i].id === id) {
data.splice(i,1)
i=i-1 // 防止有多個id相同狀況下刪除不乾淨
} else {
if (data[i]['children'] && data[i]['children'].length) {
deleteNode(data[i]['children'],id)
}else{
continue
}
}
}
return
}
複製代碼
// 修改樹
function updateNode(data,id,attr,callback) {
for(let i =0;i<data.length;i++) {
if(data[i].id === id) {
if (typeof callback == 'function') {
data[i][attr] = callback(data[i])
} else {
data[i][attr] = callback
}
continue
}
if (data[i]['children'] && data[i]['children'].length) {
updateNode(data[i]['children'],id,attr,callback)
}
}
}
複製代碼
例如咱們須要往id=0節點增長一個屬性enName:'江西',只須要:updateNode(tree,0,'enName','jiangxi') 假如咱們須要判斷id=0節點下是否有children,若是有,咱們增長一個hasChild:true,因此callback參數也能夠傳入一個回調函數,第一個參數爲當前節點bash
updateNode(tree,'12',0,(node)=>{
return node.children && node.children.length ? true:false
})
複製代碼
function formPath(data,parentId=[]) {
for (let i = 0;i<data.length;i++) {
data[i].path = parentId.concat(data[i].id)
if(data[i].children && data[i].children.length){
formPath(data[i].children,data[i].path)
}
}
}
formPath(tree)
複製代碼
function nodeMoveUpOrDown(data,id,flag=1) {
for(let i = 0;i<data.length;i++) {
if(data[i].id === id && flag === 1 && i!== data.length-1) {
const temp = data[i+1]
data[i+1] = data[i]
data[i] = temp
}
if(data[i].id === id && flag === 0 && i!== 0) {
const temp = data[i-1]
data[i-1] = data[i]
data[i] = temp
}
if(data[i].children && data[i].children.length) {
nodeMoveUpOrDown(data[i].children,id,flag)
}
}
}
複製代碼
向上移動flag=0 向下移動flag=1數據結構
function nodeMove(data,current,target) {
let temp=[]
for(let i=0;i<data.length;i++){
if(data[i].id === current || data[i].id === target){
temp.push(i)
}
if(data[i].children && data[i].children.length){
nodeMove(data[i].children,current,target)
}
}
if(temp.length === 2){
let before = data[temp[0]]
data[temp[0]] = data[temp[1]]
data[temp[1]] = before
}
}
複製代碼