Antd Design 改造 TreeSelect
Antd Design 的 TreeSelect 的多選框功能,預設是父子關聯,當父選取時,自動將子全選;如果要單獨勾選父,可以將 treeCheckStrictly 屬性設定為 true,成為受控組件,解除父子關聯。
以下進行改造,將組件改造為以下使用:
- 點選一次複選框,表示選中當前節點及該節點下的所有子節點
- 點選第二次,表示選中當前節點 (取消子節點選取)
- 點選第三次,表示不選中當前節點(取消父節點選取)
首先將 treeCheckStrictly 設定為 false,自行撰寫 handleChange 函式。
const data = {
1: {
id: 1,
name: '爸爸',
children: [2, 3]
},
2: {
id: 2,
name: '小孩1',
children: []
},
3: {
id: 3,
name: '小孩3',
children: []
},
}
const getChildIdType = (
children,
selectIds,
noSelectedChildId = [],
allChildId = [],
) => {
children.forEach((childId) => {
const index = selectIds.findIndex((id) => id === childId);
// 搜尋已選,若未選中,加入 noSelectedChildId
index === -1 && noSelectedChildId.push(childId);
allChildId.push(childId);
if (
data[childId].children &&
data[childId].children.length > 0
) {
// 還有下層節點
getChildIdType(
data[childId].children,
selectIds,
noSelectedChildId,
allChildId,
);
}
});
return { noSelectedChildId, allChildId };
};
const handleChange = (value, label, extra) => {
let selectIds = value.map((item) => item.value);
if (
extra.triggerValue &&
data[extra.triggerValue].children.length > 0
) {
// 不是子節點
const { noSelectedChildId: noSelectedId, allChildId: allId } =
getChildIdType(
data[extra.triggerValue].children,
selectIds,
);
if (extra.checked) {
// 父節點被選中
if (noSelectedId.length > 0) {
// 子節點沒有全部選中,則全選子節點
selectIds = [...selectIds, ...noSelectedId];
}
} else {
// 父節點取消選取
if (noSelectedId.length === 0) {
// 若子節點全選中,則全部取消選取
selectIds = value.filter((item) => !allId.includes(item.value));
// 選取父節點
selectIds.push(extra.triggerNode.props.value);
}
}
}
if (field && typeof field.onChange === 'function') {
field.onChange(selectIds);
}
};
參考資料:
- antd design TreeSelect 改造
Note. 文章中以extra.triggerNode?.props?.children來抓取小孩 node,個人在使用時不符合預期,所以改為直接抓 data 中的資料。讀者可再參考此篇文章做法。