iView 有個 Cascader防楷、Tree 組件如筛,數(shù)據(jù)要求比較嚴格(簡直弱爆了好嗎...)
問題簡述
Cascader 數(shù)據(jù)要求一覽(Tree 其實類似):
{
value: 'jiangsu',
label: '江蘇',
children: [
{
value: 'nanjing',
label: '南京',
children: [
{
value: 'fuzimiao',
label: '夫子廟',
}
]
}, {
value: 'suzhou',
label: '蘇州',
children: [
{
value: 'zhuozhengyuan',
label: '拙政園',
}, {
value: 'shizilin',
label: '獅子林',
}
]
}
]
}
即:
- value
- label
- children [可選]
發(fā)個牢騷
呃堡牡,誰的數(shù)據(jù)結構默認會是這樣的?肯定很少杨刨,幾乎沒有....不服咬我
話說就不能通過傳遞 value
晤柄、label
、children
的鍵值映射就配置 OK 了嗎妖胀,非得每個使用的地方轉一遍數(shù)據(jù)芥颈,累...就沒愛過
數(shù)據(jù)遞歸處理
好吧,做完一個項目了赚抡,稍微整理整理...
總得來說爬坑,這種數(shù)據(jù)還是比較好處理的。既然是樹結構涂臣,其實和 Cascader 組件所要求的數(shù)據(jù)格式基本類似盾计,無非字段名稱不一樣,字段可能更多而已肉康。
比如項目中某個需要展示部分數(shù)據(jù):
[
{
"department_id": 1,
"department_name": "Test",
"super_department_id": "0",
"child_departments": [
{
"department_id": "34",
"department_name": "修圖",
"super_department_id": "1",
"child_departments": []
},
{
"department_id": "35",
"department_name": "系統(tǒng)研發(fā)",
"super_department_id": "1",
"child_departments": [
{
"department_id": "48",
"department_name": "測試組",
"super_department_id": "35",
"child_departments": []
},
{
"department_id": "49",
"department_name": "產品組",
"super_department_id": "35",
"child_departments": []
},
{
"department_id": "50",
"department_name": "運營",
"super_department_id": "35",
"child_departments": []
},
{
"department_id": "51",
"department_name": "技術開發(fā)組",
"super_department_id": "35",
"child_departments": []
}
]
}
]
}
]
那么需要做的轉換如下:
- department_id -> value
- department_name -> label
- children -> child_departments
這個做個簡單的遞歸就解決了闯估,代碼、注釋如下:
/**
* tree 數(shù)據(jù)轉換
* @param {Array} tree 待轉換的 tree
* @return {Array} 轉換后的 tree
*/
function convertTree (tree) {
const result = []
// 遍歷 tree
tree.forEach((item) => {
// 解構賦值
let {
department_id: value,
department_name: label,
child_departments: children
} = item
// 如果有子節(jié)點吼和,遞歸
if (children) {
children = convertTree(children)
}
result.push({
value,
label,
children
})
})
return result
}
最終得到數(shù)據(jù)如下:
[
{
"value": 1,
"label": "Test",
"children": [
{
"value": "34",
"label": "修圖",
"children": []
},
{
"value": "35",
"label": "系統(tǒng)研發(fā)",
"children": [
{
"value": "48",
"label": "測試組",
"children": []
},
{
"value": "49",
"label": "產品組",
"children": []
},
{
"value": "50",
"label": "運營",
"children": []
},
{
"value": "51",
"label": "技術開發(fā)組",
"children": []
}
]
}
]
}
]
貌似結束了
其實好像也就那么回事涨薪,十來行代碼就敲定了。
但是炫乓,回頭一想刚夺,也不對,每種數(shù)據(jù)都要寫個轉換末捣,也是神煩 = =
好吧侠姑,繼續(xù)優(yōu)化優(yōu)化吧...
其實可以把遞歸函數(shù)再改改:
/**
* tree 數(shù)據(jù)轉換
* @param {Array} tree 待轉換的 tree
* @param {Object} map 鍵值對映射
* @return {Array} 轉換后的 tree
*/
function convertTree (tree, map) {
const result = []
// 遍歷 tree
tree.forEach((item) => {
// 讀取 map 的鍵值映射
const value = item[ map.value ]
const label = item[ map.label ]
let children = item[ map.children ]
// 如果有子節(jié)點,遞歸
if (children) {
children = convertTree(children, map)
}
result.push({
value,
label,
children
})
})
return result
}
就是增加了一個 map
參數(shù)箩做,用于指定 value
莽红、label
、children
的字段映射:
{
value: 'department_id',
label: 'department_name',
children: 'child_departments'
}
這樣這個遞歸方法就可以抽出來了邦邦,需要轉換的地方安吁,調這個方法就行了
感覺可以提個 feature
再來個復雜點的數(shù)據(jù)處理
在做部門展示權限的時候,遇到個問題燃辖,簡化如下:
- 如果一個節(jié)點有權限鬼店,那么顯示該節(jié)點,且顯示所屬的父節(jié)點
- 如果該節(jié)點有權限黔龟,且該節(jié)點有子節(jié)點妇智,子節(jié)點全部顯示
用圖描述一下好了:
- A 為 root 節(jié)點
- 綠色表示有權限
需要將上面的轉換得到如下 tree 結構:
用數(shù)據(jù)來說話就是:
[
{
"name": "A",
"children": [
{
"name": "B",
}, {
"name": "C",
"children": [
{
"name": "E",
"visible": true
}, {
"name": "F"
}
]
}, {
"name": "D",
"visible": true,
"children": [
{
"name": "G"
}, {
"name": "H"
}, {
"name": "I"
}
]
}
]
}
]
轉成:
[
{
"name": "A",
"children": [
{
"name": "C",
"children": [
{
"name": "E",
"visible": true
}
]
}, {
"name": "D",
"visible": true,
"children": [
{
"name": "G"
}, {
"name": "H"
}, {
"name": "I"
}
]
}
]
}
]
初看一臉懵逼
再看還是一臉懵逼....
細細捋一捋...
- 遍歷樹
- 如果當前節(jié)點有權限滥玷,塞進來
- 如果當前節(jié)點無權限,并且無子節(jié)點巍棱,拋棄
- 如果當前節(jié)點無權限惑畴,遍歷子節(jié)點(重復如上)
嗯~ o( ̄▽ ̄)o,就是這樣的...
這里有個技巧拉盾,就是使用 Array.prototype.filter()
// 原始數(shù)據(jù)
const raw = [
{
"name": "A",
"children": [
{
"name": "B",
}, {
"name": "C",
"children": [
{
"name": "E",
"visible": true
}, {
"name": "F"
}
]
}, {
"name": "D",
"visible": true,
"children": [
{
"name": "G"
}, {
"name": "H"
}, {
"name": "I"
}
]
}
]
}
]
/**
* Tree 過濾
* @param {Array} tree 待過濾的 tree
* @return {Array} 已過濾的 tree
*/
function filterTree (tree) {
let result = []
// filter 遍歷
result = tree.filter((item) => {
// 如果有權限
if (item.visible) {
return true
// 如果有子節(jié)點桨菜,遞歸子節(jié)點
// 如果有權限豁状,返回的值應該為非空數(shù)組
} else if (item.children && item.children.length > 0) {
item.children = filterTree(item.children)
return item.children.length > 0
// 拋棄
} else {
return false
}
})
return result
}
console.log( JSON.stringify(filterTree(raw), null, 4) )
// 打印結果
// [
// {
// "name": "A",
// "children": [
// {
// "name": "C",
// "children": [
// {
// "name": "E",
// "visible": true
// }
// ]
// },
// {
// "name": "D",
// "visible": true,
// "children": [
// {
// "name": "G"
// },
// {
// "name": "H"
// },
// {
// "name": "I"
// }
// ]
// }
// ]
// }
// ]
其實也就十來行...
在線演示鏈接:https://jsfiddle.net/Roam/5jb0r8y5/
總結
- 遞歸是個好東西捉偏,能省很多代碼(讓我想起一個面試題...淡淡的憂傷)
- 代碼寫得不順手,肯定哪里有問題
- 知乎上前后端就是倆冤家
今年本來打算告別后臺管理開發(fā)泻红,找個移動開發(fā)的工作
不想局限于 PC夭禽,不想成為一個擰螺絲的,不想看見 IE6
無奈之前做的全是 PC 后臺管理項目谊路,沒有移動經(jīng)驗讹躯,逛了一圈又回去了
如果只局限于當前的工作內容,也就那樣了缠劝,以后也就真的那樣了
啊潮梯,Hexo 皮膚還沒寫完啊,許久沒動了....
少年...
—— 2018/05/29 By Live惨恭, Haze.