JavaScript将具有父子关系的原始数据格式化成树形结构数据(id,pid)
前几天遇到一个树型组件(类似树形菜单)数据格式化的问题,由于后台把原始查询的数据直接返回给前端,父子关系并未构建,因此需要前端JS来完成,后台返回的数据和下面的测试数据相似。
- var data=[
- {id:1,pid:0,text:'A'},
- {id:2,pid:4,text:"E[父C]"},
- {id:3,pid:7,text:"G[父F]"},
- {id:4,pid:1,text:"C[父A]"},
- {id:5,pid:6,text:"D[父B]"},
- {id:6,pid:0,text:'B'},
- {id:7,pid:4,text:"F[父C]"}
- ];
我们可以发现上面的测试数据有几个特点,父节点与子节点不是顺序排列的,也就是说按照id的顺序,并不是先有父节点,然后有下面的子节点,顺序是混乱的,再就是父子层级有很多,这里是3层。总结为:顺序混乱,层级未知。
如果是顺序排列,层级固定,可以投机取巧,写法相对简单,但是这里恰恰相反。因此给格式化造成了一定的困难,当遇到层级未知的时候,一般都会想到递归的写法,这里我感觉用递归也不好做,因此我也就没有向这方面去深入思考,这里就也不做多的说明。
那么我的做法比起递归来讲更容易理解,先看下代码。
- function toTreeData(data){
- var pos={};
- var tree=[];
- var i=0;
- while(data.length!=0){
- if(data[i].pid==0){
- tree.push({
- id:data[i].id,
- text:data[i].text,
- children:[]
- });
- pos[data[i].id]=[tree.length-1];
- data.splice(i,1);
- i--;
- }else{
- var posArr=pos[data[i].pid];
- if(posArr!=undefined){
- var obj=tree[posArr[0]];
- for(var j=1;j<posArr.length;j++){
- obj=obj.children[posArr[j]];
- }
- obj.children.push({
- id:data[i].id,
- text:data[i].text,
- children:[]
- });
- pos[data[i].id]=posArr.concat([obj.children.length-1]);
- data.splice(i,1);
- i--;
- }
- }
- i++;
- if(i>data.length-1){
- i=0;
- }
- }
- return tree;
- }
前面的测试数据经过上面代码中的方法格式化后如下:
- [
- {
- "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,也就是说,循环内部会引起数组长度的改变。这里就几个关键点做一下说明。
- 为什么要用死循环?顺序混乱,如果单次循环,子节点出现在父节点之前,子节点不好处理,这里做一个死循环相当于先把父节点全部找出,但是这里又不是简单的先把所有的父节点找出,找的同时,如果这个节点父节点已经找到,那么可以继续做后续操作;
- 如何建立层级关系?代码中有一个变量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":[0],
- "2":[0,0,1],
- "3":[0,0,0,0],
- "4":[0,0],
- "5":[1,0],
- "6":[1],
- "7":[0,0,0]
- }
JavaScript将具有父子关系的原始数据格式化成树形结构数据(id,pid)的更多相关文章
- JS 将有父子关系的数组转换成树形结构数据
将类似如下数据转换成树形的数据 [{ id: 1, name: '1', }, { id: 2, name: '1-1', parentId: 1 }, { id: 3, name: '1-1-1', ...
- C# 把带有父子关系的数据转化为------树形结构的数据 ,以及 找出父子级关系的数据中里面的根数据Id
紧接上一篇,将List<Menu>的扁平结构数据, 转换成树形结构的数据 返回给前端 , 废话不多说,开撸! --------------------- 步骤: 1. 建 Menu ...
- oracle处理节点之间的父子关系
通常当与树的结构之间的关系处理,这是一个很复杂的事情,我们可以通过程序代码去逐层遍历父或子节点,这样做的缺点是很明显,效率不高,操作复杂性是比较大的.而当我们使用Oracle当数据库,我们可以有一个简 ...
- Vue 组件&组件之间的通信 之 非父子关系组件之间的通信
Vue中不同的组件,即使不存在父子关系也可以相互通信,我们称为非父子关系通信: 我们需要借助一个空Vue实例,在不同的组件中,使用相同的Vue实例来发送/监听事件,达到数据通信的目的: 实例: 初始加 ...
- 个人永久性免费-Excel催化剂功能第68波-父子结构表转换之父子关系BOM表拆分篇
Excel中制造业行业中,有一个非常刚需的需求是对BOM(成品物料清单)的拆解,一般系统导出的BOM表,是经过压缩处理的,由父子表结构的方式存储数据.对某些有能力使用SAP等专业ERP软件的工厂来说, ...
- Vue_(组件通讯)非父子关系组件通信
Vue单项数据流 传送门 Vue中不同的组件,即使不存在父子关系也可以相互通信,我们称为非父子关系通信 我们需要借助一个空Vue实例,在不同的组件中,使用相同的Vue实例来发送/监听事件,达到数据通信 ...
- Logstash 父子关系 配置
最近在使用Lostash的过程中遇到了一个问题:在一个log文件里包含两类数据,而且两类数据之间存在父子关系,那如何使用lostash的configuration实现这个需求呢 思路: 首先定义父事件 ...
- margin collapse 之父子关系的DIV
打算花点时间将知识整理一下,虽然平时现用现查都能完成工作,可是当遇到面试这种事情的时候,临时查就来不及了... 关于margin,整理若干知识点如下: 一:父子关系的DIV标签以及未加margin时的 ...
- iOS 父子关系
1.面向对象特征,类的继承 成员变量(实例变量) 子类继承父类所有功能,只能直接(访问)调用父类中的.h中的protect和public成员变量(实例变量)及方法, .h中的私有的成员变量,子类不能直 ...
随机推荐
- Linux 内核驱动--多点触摸接口【转】
转自:http://blog.csdn.net/joard_yang/article/details/6225937 译自:linux-2.6.31.14/Documentation/input/mu ...
- 一步一步搭建11gR2 rac+dg之DG 机器配置(七)【转】
DG 机器配置 转自: 一步一步搭建11gR2 rac+dg之DG 机器配置(七)-lhrbest-ITPUB博客http://blog.itpub.net/26736162/viewspace-12 ...
- MySQL 删除数据
删除数据的语句有三种:DELETE.DROP.TRUNCATE. 1.DELETE语句 DELETE 语句用于删除表中的行. 语法 DELETE FROM 表名称 WHERE 列名称 = 值 例如 - ...
- day10作业
1.Java中,用{}括起来的代码称为代码块. 代码块分为局部代码块,构造代码块,静态代码块,同步代码块 局部代码块:在方法中出现,限定生命周期,及早释放,提高内存利用率 构造代码块:在类中方法外出现 ...
- 产看Linux运行时间
Linux下如何查看系统启动时间和运行时间 1.uptime命令输出:16:11:40 up 59 days, 4:21, 2 users, load average: 0.00, 0.01, 0.0 ...
- 最大子段和(Max Sum)
Max Sum. The following is an instance. a) (-2,11,-4,13,-5,-2) 思路: 最大子段和:给定一个序列(元素可正可负),找出其子序列中元素和 ...
- CentOS6.5配置rsyslog
如何在RHEL 6.5安装和配置rsyslog现在7.6版本/ CentOS的6.5 .The情况是,安装和RHEL / CentOS的6.5安装rsyslog现在集中式日志服务器上.所有的客户端服务 ...
- C/C++经典面试题
1.指向数组的指针 和 指向数组首元素的指针 2018-03-07 昨天在牛客上看到这么一道C语言面试题,挺经典的,特来分享给大家. 程序如下,问输出结果 #include <stdio.h&g ...
- mac 用密钥远程登陆
window远程登陆命令:mstsc A为本地主机(即用于控制其他主机的机器) ;B为远程主机(即被控制的机器Server), 假如ip为192.168.60.110;A和B的系统都是Linux 在A ...
- 再议js的传递和深复制
病理 基本类型的传递就是按值传递,比如说 var a = 1; var b = a; b = 3; console.log(a,b);//1,3 很明显,a的值并未因为b的值改变而变化,这是因为a只是 ...