element ui Cascader 级联选择器 处理未全选时去除父节点值,选中父节点时去除子节点值

目前我这边的需求时:当用户的选择,只保留最顶层的选中节点

如果选中了父节点,则移除其所有子孙节点以及它的祖先节点(因为选中父节点代表选中整个分支,所以不需要再显示子节点;同时,如果存在祖先节点,那么祖先节点也会因为当前父节点的选中而变成部分选中,但我们希望只保留当前父节点,移除祖先节点)。
如果只选中了子节点(没有选中任何父节点),则移除这些子节点的所有父节点(即只显示叶子节点)

多层级选中逻辑处理:

  1. 需要同时处理父节点、子节点、祖先节点的复杂选中关系
  2. 当选中父节点时,需要自动移除其所有子节点和祖先节点
  3. 当只选中子节点时,需要移除所有父级节点
  4. 处理节点间的嵌套关系(父子、祖孙等)

性能优化:

  1. 递归遍历子节点时可能遇到深层嵌套数据结构
  2. 需要高效处理大规模节点数据集
  3. 使用Set进行去重和快速查找

状态一致性维护:

  1. 需要确保最终选中的key集合与级联选择器的实际状态一致
  2. 处理Element UI级联选择器返回的选中节点数据结构
  3. 协调flat()展开的选中值和节点树结构的关系

具体代码实现方式:

<template>
  <el-cascader
    ref="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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值