很实用的树形数据操做

在实际工做中,树形数据很常见,例如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
    }
}
复制代码
相关文章
相关标签/搜索