JavaScript将具备父子关系的原始数据格式化成树形结构数据(id,pid)

前几天遇到一个树型组件(相似树形菜单)数据格式化的问题,因为后台把原始查询的数据直接返回给前端,父子关系并未构建,所以须要前端JS来完成,后台返回的数据和下面的测试数据类似。前端

1 var data=[
2 {id:1,pid:0,text:'A'},
3 {id:2,pid:4,text:"E[父C]"},
4 {id:3,pid:7,text:"G[父F]"},
5 {id:4,pid:1,text:"C[父A]"},
6 {id:5,pid:6,text:"D[父B]"},
7 {id:6,pid:0,text:'B'},
8 {id:7,pid:4,text:"F[父C]"}
9 ];

咱们能够发现上面的测试数据有几个特色,父节点与子节点不是顺序排列的,也就是说按照id的顺序,并非先有父节点,而后有下面的子节点,顺序是混乱的,再就是父子层级有不少,这里是3层。总结为:顺序混乱,层级未知。数组

若是是顺序排列,层级固定,能够投机取巧,写法相对简单,可是这里偏偏相反。所以给格式化形成了必定的困难,当遇到层级未知的时候,通常都会想到递归的写法,这里我感受用递归也很差作,所以我也就没有向这方面去深刻思考,这里就也不作多的说明。测试

那么个人作法比起递归来说更容易理解,先看下代码。spa

 1 function toTreeData(data){
 2     var pos={};
 3     var tree=[];
 4     var i=0;
 5     while(data.length!=0){
 6         if(data[i].pid==0){
 7             tree.push({
 8                 id:data[i].id,
 9                 text:data[i].text,
10                 children:[]
11             });
12             pos[data[i].id]=[tree.length-1];    
13             data.splice(i,1);
14             i--;
15         }else{
16             var posArr=pos[data[i].pid];
17             if(posArr!=undefined){
18                 
19                 var obj=tree[posArr[0]];
20                 for(var j=1;j<posArr.length;j++){
21                     obj=obj.children[posArr[j]];
22                 }
23 
24                 obj.children.push({
25                     id:data[i].id,
26                     text:data[i].text,
27                     children:[]
28                 });
29                 pos[data[i].id]=posArr.concat([obj.children.length-1]);
30                 data.splice(i,1);
31                 i--;
32             }
33         }
34         i++;
35         if(i>data.length-1){
36             i=0;
37         }
38     }
39     return tree;
40 }

前面的测试数据通过上面代码中的方法格式化后以下:code

[
    {
        "id": 1,
        "text": "A",
        "children": [
            {
                "id": 4,
                "text": "C[父A]",
                "children": [
                    {
                        "id": 7,
                        "text": "F[父C]",
                        "children": [
                            {
                                "id": 3,
                                "text": "G[父F]",
                                "children": []
                            }
                        ]
                    },
                    {
                        "id": 2,
                        "text": "E[父C]",
                        "children": []
                    }
                ]
            }
        ]
    },
    {
        "id": 6,
        "text": "B",
        "children": [
            {
                "id": 5,
                "text": "D[父B]",
                "children": []
            }
        ]
    }
]

原理很简单,使用一个死循环来遍历数组,循环跳出的条件是数组的长度为0,也就是说,循环内部会引发数组长度的改变。这里就几个关键点作一下说明。blog

  1. 为何要用死循环?顺序混乱,若是单次循环,子节点出如今父节点以前,子节点很差处理,这里作一个死循环至关于先把父节点所有找出,可是这里又不是简单的先把全部的父节点找出,找的同时,若是这个节点父节点已经找到,那么能够继续作后续操做;
  2. 如何创建层级关系?代码中有一个变量pos,这个用于保存每一个已添加到tree中的节点在tree中位置信息,好比上面测试数据父节点A添加到tree后,那么pos中增长一条数据,pos={”1“:[0]},1就是父节点A的id,这样写便于查找,[0]表示父节点A在tree的第一个元素,即tree[0],若是某个位置信息为[1,2,3],那么表示这个节点在tree[1].children[2].children[3],这里的位置关系其实就是父子的层级关系。

上面的测试数据的pos信息以下:递归

1 {
2     "1":[0],
3     "2":[0,0,1],
4     "3":[0,0,0,0],
5     "4":[0,0],
6     "5":[1,0],
7     "6":[1],
8     "7":[0,0,0]
9 }
相关文章
相关标签/搜索