7

背景

在前端开发中,有一种组件是每个前端都绕不过去的,树组件。在业务中像目录结构、组织架构、行政区域划分这些都是典型的树组件使用场景。一般来说,前端也就是拿来一个封装好的控件,然后传入符合要求的数据结构就完事了。但是,有的时候我们拿到的东西可能并不完美,比如服务端给我们返回了一个列表,列表中每一项之间的父子关系通过id与parentId来确定,那么问题来了,我们如何在前端把这样的列表数据转换成树结构的数据呢?想过么?做过么?做得出来么?
我搜索了一大圈,发现绝大部分都是把代码一贴就完事,根本不讲思路是什么,为了能一劳永逸的解决这个问题,我觉得先把思路理清是最重要的,至于怎么实现,就是coding的问题了,coding就看每个人心情了,每个人都有自己喜欢的方式,个人不建议把coding写死,僵化。

思路分析

需求是什么?
图片描述

大概是这个样子,应该一目了然了。

先说一下整体思路,根据parentId和id把数组中的每一项的父节点找到,并将自己作为父节点的children中的一项,所有的数据项都处理完毕后,其实就差不多了,最后我们把根节点找到并返回,转换完成。

执行步骤

  1. 遍历每一个列表项,对比该项(currentItem)parentId与列表内所有项的id,根据对比结果做后续处理
  2. 如果该项parentId与列表中某项(parentItem)id相等,那么把currentItem作为parentItem的孩子。也就是把currentItem作为parentItem的children中的一项。
  3. 执行完上述过程后,列表中对应的父子关系就已经处理完毕了,此时我们需要找出根节点就可以了,判断根节点的方法很简单,就是parentId为null的项。

代码

const List = [
    {id: 1, name: 'child1', parentId: 0},
    {id: 2, name: 'child2', parentId: 0},
    {id: 6, name: 'child2_1', parentId: 2},
    {id: 0, name: 'root', parentId: null},
    {id: 5, name: 'child1_2', parentId: 1},
    {id: 4, name: 'child1_1', parentId: 1},
    {id: 3, name: 'child3', parentId: 0},
    {id: 7, name: 'child3_1', parentId: 3}
]

function ListToTree (list) {
    const copyList = list.slice(0)
    const tree = []
    for (let i = 0;i < copyList.length;i++) {
        // 找出每一项的父节点,并将其作为父节点的children
        for (let j = 0;j < copyList.length;j++) {
            if (copyList[i].parentId === copyList[j].id) {
                if (copyList[j].children === undefined) {
                    copyList[j].children = []
                }
                copyList[j].children.push(copyList[i])
            }
        }
        // 把根节点提取出来,parentId为null的就是根节点
        if (copyList[i].parentId === null) {
            tree.push(copyList[i])
        }
    }
    return tree
}

const tree = ListToTree(List)
console.log(JSON.stringify(tree))

上面代码直接扔到浏览器中即可运行,可自行看看结果。这里先把结果放在下面,供参考。
[{"id":0,"name":"root","parentId":null,"children":[{"id":1,"name":"child1","parentId":0,"children":[{"id":5,"name":"child1_2","parentId":1},{"id":4,"name":"child1_1","parentId":1}]},{"id":2,"name":"child2","parentId":0,"children":[{"id":6,"name":"child2_1","parentId":2}]},{"id":3,"name":"child3","parentId":0,"children":[{"id":7,"name":"child3_1","parentId":3}]}]}]
以上结果放到https://www.bejson.com/jsoned...中查看,效果更佳。

总结

列表转树的过程,我这里用了两层循环,然后利用了js的对象引用机制,将列表转成了树,其实这个过程中已经改变了原有的列表数据结构(循环结束后打印copyList即可看到结果),所以在第一步的时候才先复制了一个列表进来。这里应该还有可优化的地方,欢迎大家提供更多更好的思路,恳请在补充新的方案时,先把思路说清楚,切勿直接扔代码上来。交流、沟通、理解效果才好。


水电
534 声望33 粉丝