目前我這邊的需求時:當用戶的選擇,只保留最頂層的選中節點
如果選中了父節點,則移除其所有子孫節點以及它的祖先節點(因為選中父節點代表選中整個分支,所以不需要再顯示子節點;同時,如果存在祖先節點,那么祖先節點也會因為當前父節點的選中而變成部分選中,但我們希望只保留當前父節點,移除祖先節點)。
如果只選中了子節點(沒有選中任何父節點),則移除這些子節點的所有父節點(即只顯示葉子節點)
多層級選中邏輯處理:
- 需要同時處理父節點、子節點、祖先節點的復雜選中關系
- 當選中父節點時,需要自動移除其所有子節點和祖先節點
- 當只選中子節點時,需要移除所有父級節點
- 處理節點間的嵌套關系(父子、祖孫等)
性能優化:
- 遞歸遍歷子節點時可能遇到深層嵌套數據結構
- 需要高效處理大規模節點數據集
- 使用Set進行去重和快速查找
狀態一致性維護:
- 需要確保最終選中的key集合與級聯選擇器的實際狀態一致
- 處理Element UI級聯選擇器返回的選中節點數據結構
- 協調flat()展開的選中值和節點樹結構的關系
具體代碼實現方式:
<template><el-cascaderref="cascaderRef"v-model="selectedOptions":options="options":props="{ multiple: true }"@change="handleChange"></el-cascader>
</template><script>
export default {data() {return {selectedOptions: [],options: [{value: 'parent1',label: 'Parent 1',children: [{ value: 'child1', label: 'Child 1' },{ value: 'child2', label: 'Child 2' }]},{value: 'parent2',label: 'Parent 2',children: [{ value: 'child1', label: 'Child 1' },{ value: 'child2', label: 'Child 2' }]}],selectKeys:[]};},methods: {// 選中handleChange(e) {// 獲取當前選中的值(去重)const selectData = [...new Set(e.flat())];// 獲取所有選中的節點const checkedNodes = this.$refs.cascaderRef.getCheckedNodes();// 找出所有選中的父節點(非葉子節點)const parentNodes = checkedNodes.filter((node) => node.children && node.children.length > 0);// 找出所有選中的子節點const childrenNodes = checkedNodes.filter((node) => node.children.length == 0);// 只選擇了子節點(沒有父節點) // 選中了至少一個父節點this.selectKeys =parentNodes.length === 0? this.getChildren(checkedNodes, selectData): this.getParent(parentNodes, selectData, childrenNodes);console.log(this.selectKeys, '========>');},// 處理選中父節點,去除子節點和父節點的父節點getParent(parentNodes, selectAllKey, childrenNodes) {// 創建兩個Set用于存儲需要移除的節點const nodesToRemove = new Set(); // 所有需要移除的節點const parentValues = new Set(); // 所有選中的父節點值// 處理每個選中的父節點parentNodes.forEach((parentNode) => {// 添加當前父節點到集合parentValues.add(parentNode.value);console.log(parentNode, 'parentNode');// 1. 收集當前父節點的所有上級節點(父節點的父節點)if (parentNode.pathNodes && parentNode.pathNodes.length > 1) {const parentPath = parentNode.pathNodes.filter((item) => !item.checked); // 移除父級節點選中數據(當前節點)parentPath.forEach((path) => nodesToRemove.add(path.value));}// 2. 遞歸收集所有子節點的值const collectChildrenValues = (children) => {children.forEach((child) => {nodesToRemove.add(child.value);if (child.children) {collectChildrenValues(child.children);}});};collectChildrenValues(parentNode.children);});// 3. 最終選中的值 = 原始選中值 - 需要移除的節點const finalSelected = selectAllKey.filter((value) => !nodesToRemove.has(value));// 獲取當前選中的子節點,過濾掉處理過的子節點const childrenList =childrenNodes.filter((item) => !nodesToRemove.has(item.value)).map((item) => item.value) || [];const selectKey = [...new Set([...finalSelected, ...childrenList])];// console.log('處理父節點結果:', selectAllKey, {// finalSelected,// selectKey,// removedNodes: [...nodesToRemove],// parentNodes: [...parentValues],// });return selectKey;},// 處理只選中子節點的情況(移除父節)getChildren(checkedNodes, selectAllKey) {// 收集所有子節點的父級const parentPaths = [];checkedNodes.forEach((item) => {// 移除當前節點值,保留父級路徑if (item.path && item.path.length > 1) {const path = item.path.slice(0, -1); // 移除最后一個元素(當前節點)parentPaths.push(...path);}});// 去重父級const uniqueParentPaths = [...new Set(parentPaths)];// 過濾掉所有父級,只保留子節點const selectKey = selectAllKey.filter((item) => !uniqueParentPaths.includes(item));// console.log('只選擇子節點結果:', {// selectKey, //當前選中// parentPaths: uniqueParentPaths, //父級節點// originalSelect: selectData, //所有選中數據(包含父節點)// });return selectKey;},}
};
</script>