目前我这边的需求时:当用户的选择,只保留最顶层的选中节点
如果选中了父节点,则移除其所有子孙节点以及它的祖先节点(因为选中父节点代表选中整个分支,所以不需要再显示子节点;同时,如果存在祖先节点,那么祖先节点也会因为当前父节点的选中而变成部分选中,但我们希望只保留当前父节点,移除祖先节点)。
如果只选中了子节点(没有选中任何父节点),则移除这些子节点的所有父节点(即只显示叶子节点)
多层级选中逻辑处理:
- 需要同时处理父节点、子节点、祖先节点的复杂选中关系
- 当选中父节点时,需要自动移除其所有子节点和祖先节点
- 当只选中子节点时,需要移除所有父级节点
- 处理节点间的嵌套关系(父子、祖孙等)
性能优化:
- 递归遍历子节点时可能遇到深层嵌套数据结构
- 需要高效处理大规模节点数据集
- 使用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>