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) => {
let cache = []
//這裏只是爲了方便查看extra的數據,可以省略這步
let checkedNodes = JSON.stringify(extra.allCheckedNodes, function (key, value) {
if (typeof value === 'object' && value !== null) {
if (cache.indexOf(value) !== -1) {
return;
}
cache.push(value);
}
return value;
})
cache = null
let count = getCheckedCount(checkedNodes)
if (isObjEmpty(checkedNodes)) {
checkedNodes = []
}
return {checkedNodes, count}
}
export const getCheckedCount = (checkedNodes) => {
if (!isObjEmpty(checkedNodes)) {
try {
checkedNodes = JSON.parse(checkedNodes)
} catch (e) {
}
let quantity = 0
for (let i = 0; i < checkedNodes.length; i++) {
let checkedNode = checkedNodes[i]
if (checkedNode.children) {
checkedNode = checkedNode.children
quantity = quantity + getCheckedCount(checkedNode)
} else {
quantity = quantity + 1
continue
}
}
return quantity
} else {
return 0
}
}