前言
最近一直在做的是一個後臺管理系統,更偏向於對資料的一個處理.其中最典型的資料處理,就是樹形結構資料,比如用在側邊欄選單,比如去描述各部門之間的上下級關係等等.有的時候後端勤快一點,把它處理了,但是萬一沒有呢?那就需要前端去處理嘍!另外補一句:坑爹的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);
複製程式碼