antd的TreeSelect元件在處理例如公司層級、學科系統、分類目錄等等的樹形選擇需求時很好用。
在使用這個元件時,我們往往需要獲取所選中的所有節點以及所選中的所有子節點的數量。
檢視TreeSelect的api找到了元件的選中回撥方法onChange
在理解onChange方法的引數含義前,要先知道TreeSelect元件的資料格式
onChange方法有三個引數,value表示所選中的節點的value欄位值,label代表所選中的節點的title欄位值。而最後一個extra引數是獲取所選中子節點數量的關鍵,它是一個Object物件。
通過檢視extra的資料,找到了allCheckedNodes這個欄位。這個欄位裡放置著所有被選中的節點的資料。其格式如下
[
{
"node":{
"key":"1",
"ref":null,
"props":{
"title":"全體老師",
"value":"1",
"children":[
{
"key":"1-1",
"ref":null,
"props":{
"title":"老師1",
"value":"1-1",
"children":[
]
},
"_owner":null,
"_store":{
}
},
{
"key":"1-2",
"ref":null,
"props":{
"title":"老師2",
"value":"1-2",
"children":[
]
},
"_owner":null,
"_store":{
}
},
{
"key":"1-3",
"ref":null,
"props":{
"title":"老師3",
"value":"1-3",
"children":[
]
},
"_owner":null,
"_store":{
}
},
{
"key":"1-4",
"ref":null,
"props":{
"title":"老師4",
"value":"1-4",
"children":[
]
},
"_owner":null,
"_store":{
}
},
{
"key":"1-5",
"ref":null,
"props":{
"title":"老師5",
"value":"1-5",
"children":[
]
},
"_owner":null,
"_store":{
}
},
{
"key":"1-6",
"ref":null,
"props":{
"title":"老師6",
"value":"1-6",
"children":[
]
},
"_owner":null,
"_store":{
}
},
{
"key":"1-7",
"ref":null,
"props":{
"title":"老師7",
"value":"1-7",
"children":[
]
},
"_owner":null,
"_store":{
}
},
{
"key":"1-8",
"ref":null,
"props":{
"title":"老師8",
"value":"1-8",
"children":[
]
},
"_owner":null,
"_store":{
}
},
{
"key":"1-9",
"ref":null,
"props":{
"title":"老師9",
"value":"1-9",
"children":[
]
},
"_owner":null,
"_store":{
}
}
]
},
"_owner":null,
"_store":{
}
},
"pos":"0-1",
"children":[
{
"pos":"0-1-0"
},
{
"pos":"0-1-1"
},
{
"pos":"0-1-2"
},
{
"pos":"0-1-3"
},
{
"pos":"0-1-4"
},
{
"pos":"0-1-5"
},
{
"pos":"0-1-6"
},
{
"pos":"0-1-7"
},
{
"pos":"0-1-8"
}
]
}
]
分析發現,allCheckedNodes物件裡的pos欄位內容是當前被選中的節點的key值,而children欄位是這個節點的被選中的所有子節點的集合陣列,而children內的物件又有可能有下一層級的子節點。
為了計算這種巢狀的多層級關係的子節點數量,我們需要用到遞迴方法。
方法思路是,一層一層的去看當前物件有沒有children欄位,如果沒有,說明它是子節點,那直接讓數量加一;如果有,則說明是父節點,則遞迴呼叫方法去取其子節點內的資料。經過這樣的遞迴取數,就能計算出所有被選中的子節點的數量了。
方法程式碼如下:
export const getCheckedNodes = (extra) => {
console.log(`targetExtra`, extra)
let checkedNodes = extra.allCheckedNodes
let count = getCheckedCount(checkedNodes)
if (isObjEmpty(checkedNodes)) {
checkedNodes = []
}
return {checkedNodes, count}
}
export const getCheckedCount = (checkedNodes) => {
if (!isObjEmpty(checkedNodes)) {
let quantity = 0
for (let i = 0; i < checkedNodes.length; i++) {
let checkedNode = checkedNodes[i]
if (checkedNode.node) {
if (checkedNode.children) {
checkedNode = checkedNode.children
quantity = quantity + getCheckedCount(checkedNode)
} else {
quantity = quantity + 1
continue
}
} else {
if (checkedNode.props) {
if (checkedNode.props.children.length > 0) {
checkedNode = checkedNode.props.children
quantity = quantity + getCheckedCount(checkedNode)
} else {
quantity = quantity + 1
continue
}
}
}
}
return quantity
} else {
return 0
}
}