前言
最近一直在做的是一个后台管理系统,更偏向于对数据的一个处理.其中最典型的数据处理,就是树形结构数据,比如用在侧边栏菜单,比如去描述各部门之间的上下级关系等等.有的时候后端勤快一点,把它处理了,但是万一没有呢?那就需要前端去处理喽!另外补一句:坑爹的win10系统,又浪费了朕半天时间去重新配置环境.
第一种方案
技术点:面向对象,递归函数
可以用json-server插件去简单搭建一个服务器,提供数据支撑
代码如下:(基于vue技术栈,iview-ui框架的tree组件的一个工具函数)
// 该模块用于将普通数组去转化为树形结构的数组结构
// 导出一个构造函数,所以在使用的时候,要new一个对象
export function TreeData (a) {
// 若a为空,tree即为空数组,否则即为获取的数组数据
this.tree = a || [];
this.groups = {};
}
TreeData.prototype = {
init: function (parentid) {
// parentid的值在组件中被定义为0
this.group();
// 此时this.groups每一个parentid也只有一个子元素
return this.getDom(this.groups[parentid]);
},
group: function () {
// 该函数将普通数组处理成二级结构,属性名为父部门id,属性值为子部门的部门信息(数据形式为对象)
// 每一个拥有子部门的父部门id都将作为this.groups的属性名
for (var i = 0; i < this.tree.length; i++) {
if (this.groups[this.tree[i].parentid]) {
// 目前数据中每一个部门的部门信息中parentid都是存在的,写一个if分歧应该是为了防止后端数据的失误
// 父级已经存在,使得同一级的子级能够被追加进去
this.groups[this.tree[i].parentid].push(this.tree[i]);
} else {
// 数组元素的parentid值去做了groups的属性名,parentid实际上是数字呀,就是要将子集数据追加到父集
// this.groups对象是没有属性的,所有的parentid都将作为this.groups的属性值
this.groups[this.tree[i].parentid] = [];
this.groups[this.tree[i].parentid].push(this.tree[i]);
}
}
},
// 非常任性,使用了函数递归,手法近似于深拷贝,对象才能一层一层的放下去
getDom: function (a) {
// a即为this.groups的属性对象,如果不存在就返回为空,即后台返回的数据为空的时候
if (!a) {
return '';
}
// 重新拼接出了一个JSON字符串,所需要的树形数据结构的字符串形式,且有序排列
// this.groups仅仅提供了一个拥有两个层级的数据结构
var data = '[';
for (let i = 0; i < a.length; i++) {
// this.groups[parentid]里面的对象在group函数中被有序追加
// "expand":"true","type":"department"的添加是出于iview的tree控件和项目其他地方的需要
data += `{"title":"${a[i].departmentname}","departmentid":"${a[i].departmentid}","parentid":"${a[i].parentid}","expand":"true","type":"department"`;
// 以第一次进入该函数为例
// 因为有parentid为0的存在,所以部门里我更愿意增加一个0级部门
// 如果一级部门还有子部门,就接着拼接children属性值
data += this.getDom(this.groups[a[i].departmentid]) ? ',' : '';
// 将二级部门追加到一级部门的children属性中
data += this.getDom(this.groups[a[i].departmentid]) ? '"children":' + this.getDom(this.groups[a[i].departmentid]) : '';
if (i === a.length - 1) {
// 同层级的数据被添加完成
data += '}';
} else {
data += '},';
}
};
data += ']';
return data;
}
};
复制代码
要处理的数据:
{
"msg": "success",
"code": 200,
"data": [
{
"departmentid": 1,
"departmentname": "总部",
"parentid": 0,
"isrmv": false,
"sort": 1,
"leaderid": null,
"qxDepartmentid": 1
},
{
"departmentid": 2,
"departmentname": "总经办",
"parentid": 1,
"isrmv": false,
"sort": 1,
"leaderid": 44220,
"qxDepartmentid": null
},
{
"departmentid": 4,
"departmentname": "IT部",
"parentid": 1,
"isrmv": false,
"sort": 3,
"leaderid": null,
"qxDepartmentid": null
},
{
"departmentid": 9,
"departmentname": "技术组",
"parentid": 1,
"isrmv": false,
"sort": null,
"leaderid": null,
"qxDepartmentid": 1432010565
},
{
"departmentid": 10,
"departmentname": "财务部",
"parentid": 1,
"isrmv": false,
"sort": null,
"leaderid": null,
"qxDepartmentid": 1432014225
},
{
"departmentid": 28,
"departmentname": "总经办22",
"parentid": 1,
"isrmv": false,
"sort": null,
"leaderid": null,
"qxDepartmentid": null
},
{
"departmentid": 31,
"departmentname": "技术组1",
"parentid": 4,
"isrmv": false,
"sort": null,
"leaderid": null,
"qxDepartmentid": null
},
{
"departmentid": 32,
"departmentname": "啦啦",
"parentid": 4,
"isrmv": false,
"sort": null,
"leaderid": null,
"qxDepartmentid": null
},
{
"departmentid": 33,
"departmentname": "test23",
"parentid": 1,
"isrmv": false,
"sort": null,
"leaderid": null,
"qxDepartmentid": 33
},
{
"departmentid": 38,
"departmentname": "测试部门3",
"parentid": 1,
"isrmv": false,
"sort": null,
"leaderid": 44229,
"qxDepartmentid": 1432014228
},
{
"departmentid": 39,
"departmentname": "测试部门31",
"parentid": 38,
"isrmv": false,
"sort": null,
"leaderid": 44283,
"qxDepartmentid": 1432014229
},
{
"departmentid": 40,
"departmentname": "测试部门32",
"parentid": 38,
"isrmv": false,
"sort": null,
"leaderid": 44246,
"qxDepartmentid": 1432014230
},
{
"departmentid": 41,
"departmentname": "测试部门311",
"parentid": 39,
"isrmv": false,
"sort": null,
"leaderid": 44239,
"qxDepartmentid": 1432014231
},
{
"departmentid": 44,
"departmentname": "测试部门34",
"parentid": 38,
"isrmv": false,
"sort": null,
"leaderid": null,
"qxDepartmentid": 1432014233
}
]
}
复制代码
处理后的数据:(expand是iview-ui的tree组件决定节点是否展开的一个字段)
[
{
"children": [
{
"children": [],
"departmentid": "2",
"expand": "true",
"parentid": "1",
"title": "总经办",
"type": "department"
},
{
"children": [
{
"departmentid": "31",
"expand": "true",
"parentid": "4",
"title": "技术组1",
"type": "department"
},
{
"departmentid": "32",
"expand": "true",
"parentid": "4",
"title": "啦啦",
"type": "department"
}
],
"departmentid": "4",
"expand": "true",
"parentid": "1",
"title": "IT部",
"type": "department"
},
{
"departmentid": "9",
"expand": "true",
"parentid": "1",
"title": "技术组",
"type": "department"
},
{
"departmentid": "10",
"expand": "true",
"parentid": "1",
"title": "财务部",
"type": "department"
},
{
"departmentid": "28",
"expand": "true",
"parentid": "1",
"title": "总经办22",
"type": "department"
},
{
"departmentid": "33",
"expand": "true",
"parentid": "1",
"title": "test23",
"type": "department"
},
{
"children": [
{
"children": [
{
"departmentid": "41",
"expand": "true",
"parentid": "39",
"title": "测试部门311",
"type": "department"
}
],
"departmentid": "39",
"expand": "true",
"parentid": "38",
"title": "测试部门31",
"type": "department"
},
{
"departmentid": "40",
"expand": "true",
"parentid": "38",
"title": "测试部门32",
"type": "department"
},
{
"departmentid": "44",
"expand": "true",
"parentid": "38",
"title": "测试部门34",
"type": "department"
}
],
"departmentid": "38",
"expand": "true",
"parentid": "1",
"title": "测试部门3",
"type": "department"
}
],
"departmentid": "1",
"expand": "true",
"parentid": "0",
"title": "总部",
"type": "department"
}
]
复制代码
最终的效果图
第二种方案
关键字 id,parentId ,child
判断是root节点的方法为 parentId===0
let data = [
{id: 1, text: 't11', parentId: 0},
{id: 2, text: 't11', parentId: 0},
{id: 3, text: 't11', parentId: 1},
{id: 4, text: 't11', parentId: 1},
{id: 5, text: 't11', parentId: 3},
{id: 6, text: 't11', parentId: 2},
];
data.forEach(ele => {
// 第一次forEach遍历到所有的数组对象,不做去重,数组依旧拥有6个元素
let parentId = ele.parentId;
if (parentId === 0) {
//是根元素的hua ,不做任何操作,如果是正常的for-i循环,可以直接continue.
} else {
//如果ele是子元素的话 ,把ele扔到他的父亲的child数组中.它的父元素也可能是别人的子元素
//遍历6遍,数组依旧拥有6个元素,只不过有些有嵌套关系
data.forEach(d => {
if (d.id === parentId) {
let childArray = d.child;
// 一则避免了去给d.child声明定义空数组
// childArray为undefined时,用push方法去报undefined.push的错
if (!childArray) {
childArray = []
}
// 用push保证同级别的对象有序追加
childArray.push(ele);
d.child = childArray;
} //else的地方不做处理,保证了最深层的对象没有child属性
})
}
});
//去除重复元素
data = data.filter(ele => ele.parentId === 0);
console.log('最终等到的tree结构数据: ', data);
复制代码