在平时的开发中,咱们常常会遇到树状对象的问题,例如:多级菜单、多级部门、多级文件夹等。通常状况下,咱们在数据库中会把这些信息存成平面结构,每一条数据之间有关联字段,例如parentId和id。前端
一般的前端树组件中会要求咱们传入一个树状对象,可是在数据库中存储的都是平面结构的对象(简称平面对象),这就须要咱们将现有的数据结构进行组装。服务器的资源是宝贵的,因此咱们应该尽量的将这一部分工做交至前端来完成。因而我写了这么一段代码,但愿对你们有所帮助,若是有什么不正确的地方,欢迎指正。数据库
/**
* @conf childrenTag 子集合字段名,默认children
* @conf keyMap.id 节点惟一标识字段名,默认id
* @conf keyMap.parentId 父节点惟一标识字段名,默认parentId
*
* @method toSingle 树状对象转平面对象
* @method toList 平面对象转树状对象
*/
window.treeUtil = {
childrenTag: 'children',
keyMap: {id: 'id', parentId: 'parentId'},
toSingle: function (obj) {
if (obj instanceof Array) {
var result = [];
for (var i in obj) {
result.push(obj[i]);
if (obj[i][this.childrenTag]) {
result = result.concat(this.toSingle(obj[i][this.childrenTag]));
delete obj[i][this.childrenTag];
}
}
return result;
} else if (obj instanceof Object) {
return obj;
} else {
throw Error('It not is a Array or Object.');
}
},
toList: function (arr) {
// 查询根节点
var temp = this.findRootList(arr);
return this.findChildList(temp.rootNds, temp.otherNds);
},
findChildList: function (rootNds, childNds) {
for (var i in rootNds) {
var recordIndex = [];
rootNds[i][this.childrenTag] = [];
for (var j in childNds) {
if (childNds[j][this.keyMap.parentId] === rootNds[i][this.keyMap.id]) {
rootNds[i][this.childrenTag].push(childNds[j]);
recordIndex.push(j);
}
}
// 尽量的删去已经使用过的对象,用来减小递归时的循环次数。
// 这里为了避免让数组长度影响循环,从大到小遍历
for (var k = recordIndex.length - 1; k >= 0; k--) {
childNds.splice(recordIndex[k], 1);
}
if (childNds.length > 0) {
this.findChildList(rootNds[i][this.childrenTag], childNds);
}
}
return rootNds;
},
findRootList: function (arr) {
var rootNds = [], otherNds = [];
for (var i = 0; i < arr.length; i++) {
var flag = true;
for (var j = 0; i !== j && j < arr.length; j++) {
if (arr[i][this.keyMap.parentId] === arr[j][this.keyMap.id]) {
flag = false;
break;
}
}
if (flag) {
rootNds.push(arr[i]);
} else {
otherNds.push(arr[i]);
}
}
return {rootNds: rootNds, otherNds: otherNds};
}
};
复制代码
这里提供了两个可用的方法,toSingle和toList。toSingle是将树状对象转换为平面对象,toList反之。为了可扩展性,不要去将关联字段硬编码化,采用配置的方法:childrenTag字段和keyMap对象用来管理数据之间的关联关系。数组
接下来咱们来验证一下效果:bash
var list1 = [
{
"id": 1,
"name": "新建文件夹1",
"type": 1,
"parentId": 0,
"children": [{"id": 3, "name": "新建文件夹3", "type": 1, "parentId": 1, "children": []}, {
"id": 4,
"name": "新建文件夹4",
"type": 2,
"parentId": 1,
"children": [{"id": 8, "name": "新建文件夹8", "type": 2, "parentId": 4, "children": []}, {
"id": 9,
"name": "新建文件夹9",
"type": 2,
"parentId": 4,
"children": []
}]
}]
}, {
"id": 2,
"name": "新建文件夹2",
"type": 1,
"parentId": 0,
"children": [{
"id": 5,
"name": "新建文件夹5",
"type": 2,
"parentId": 2,
"children": [{"id": 10, "name": "新建文件夹10", "type": 2, "parentId": 5}]
}, {"id": 6, "name": "新建文件夹6", "type": 2, "parentId": 2, "children": []}, {
"id": 7,
"name": "新建文件夹7",
"type": 2,
"parentId": 2,
"children": []
}]
}
];
console.log(treeUtil.toSingle(list1));
复制代码
result: 服务器
接下来再验证一下toList:数据结构
var list2 = [
{"id": 1, "name": "新建文件夹1", "type": 1, "parentId": 0},
{"id": 3, "name": "新建文件夹3", "type": 1, "parentId": 1},
{"id": 4, "name": "新建文件夹4", "type": 2, "parentId": 1},
{"id": 8, "name": "新建文件夹8", "type": 2, "parentId": 4},
{"id": 9, "name": "新建文件夹9", "type": 2, "parentId": 4},
{"id": 2, "name": "新建文件夹2", "type": 1, "parentId": 0},
{"id": 5, "name": "新建文件夹5", "type": 2, "parentId": 2},
{"id": 10, "name": "新建文件夹10", "type": 2, "parentId": 5},
{"id": 6, "name": "新建文件夹6", "type": 2, "parentId": 2},
{"id": 7, "name": "新建文件夹7", "type": 2, "parentId": 2}
];
console.log(treeUtil.toList(list2));
复制代码
result: ui
本次分享就到这里。若有问题,请联系做者。 若是这篇文章对你有帮助,请点击喜欢来收藏此文章。this