很實用的樹形數據操做

在實際工做中,樹形數據很常見,例如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
})
複製代碼

生成path

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
    }
}
複製代碼
相關文章
相關標籤/搜索