在平時的開發中,咱們常常會遇到樹狀對象的問題,例如:多級菜單、多級部門、多級文件夾等。通常狀況下,咱們在數據庫中會把這些信息存成平面結構,每一條數據之間有關聯字段,例如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