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 中的資料。讀者可再參考此篇文章做法。