ant tree 数据的最优解

项目背景 : react + ant

ant 官网中目前只提供了 默认父子关联  或 checkStrictly(父子不关联)

注意 : 不能盲目选择父子关联 , 虽然选中父 , 子也联动确实是需要的效果 , 但有一个bug 如下图  (当选中部分子 , 所有子被选中)



解决方案 : 只能取消父子关联 , 自己去判断当前点击处是否为父 , 是父的话选中对应的所有子 , 当父为空子被选中时 , 父也应被选中



1. 将后台返回的平铺结构转成需要的树形父子结构


2. 判断不同情况下 父子选中的状态 , 目前我判断了5种 , 分别是 选中父对应子全部被选中 ; 取消父对应子全被取消 ; 父存在时单独取消子 ; 父被选中时添加子 ; 父为空时单独添加子




 

整体代码如下

    //平铺数据转树形结构
      function buildTree (data, parentId = 0) {
        let tree = []; // 用于存放结果的数组

        // 遍历数据,找到parentId匹配的项
        for (let item of data) {
          if (item.parentId === parentId) {
            // 创建一个新对象,准备添加子节点
            let node = { ...item, children: buildTree(data, item.permissionId) }; // 递归调用,处理子节点
            tree.push(node); // 将当前节点添加到结果数组中
          }
        }

        return tree;
      }            


      const result = buildTree(res3, 0);
      setTreeData(result);







  // 选中二级父,二级子也被选中,这样会有bug,当取消子以后父也被取消了
  const ontreeCheck = (keys, { checked, checkedNodes, node }) => {
    console.log('keys', keys); // 包含checked和halfChecked俩个数组,checked包含了被选中节点的id
    console.log('checked', checked); // true或false
    console.log('node', node); // 目前选中的单个节点(对象格式)
    console.log('checkedNodes', checkedNodes); // 被选中的所有节点(treeData的对象格式)

    console.log('treeData', treeData); // 转换后的所有的树形结构数据

    // 递归函数,判断一个数字是否在数组中
    function numberInArray (number, array) {
      return array.includes(number);
    }

    // 递归函数,根据父对象的 permissionId 找到所有子对象的 permissionId
    function findChildrenPermissionIds (tree, parentId) {
      let childrenPermissionIds = [];

      // 遍历每个节点
      for (let node of tree) {
        if (node.permissionId === parentId) {
          // 找到匹配的父节点,收集其所有子节点的 permissionId
          if (node.children && node.children.length > 0) {
            childrenPermissionIds = node.children.map((child) => child.permissionId);
          }
          break; // 找到匹配的父节点后可以直接跳出循环
        } else if (node.children && node.children.length > 0) {
          // 如果当前节点不是父节点,则递归地查找其子节点
          childrenPermissionIds = findChildrenPermissionIds(node.children, parentId);
          if (childrenPermissionIds.length > 0) {
            break; // 如果找到了符合条件的子节点,也可以跳出循环
          }
        }
      }

      return childrenPermissionIds;
    }

    // 递归函数根据子来找到父

    function findParentPermissionIds (permissionId, treeData) {
      for (let i = 0; i < treeData.length; i++) {
        const parent = treeData[i];
        // 查找子节点
        const child = parent.children.find((child) => child.permissionId === permissionId);
        if (child) {
          // 如果找到了匹配的子节点,则返回父节点的 permissionId
          return parent.permissionId;
        }

        // 如果子节点中还有子节点,继续递归查找
        if (parent.children && parent.children.length > 0) {
          const result = findParentPermissionIds(permissionId, parent.children);
          if (result !== null) {
            return result;
          }
        }
      }
      // 如果没有找到,则返回 null
      return null;
    }

    const parentID = treeData.map((item) => item.permissionId);

    const selectedParents = treeData.filter((parent) => keys.checked.includes(parent.permissionId));

    // 选中了父让子也被选中
    if (checked && numberInArray(node.permissionId, parentID)) {
      const aaa = findChildrenPermissionIds(treeData, node.permissionId);

      const result = keys.checked.concat(aaa);

      setCheckedKeys(result);
    } else if (!checked && numberInArray(node.permissionId, parentID)) {
      // 当取消了父以后, 让对应的子也取消
      const aaa = findChildrenPermissionIds(treeData, node.permissionId);

      const ccc = aaa.push(node.permissionId);

      const result = checkedKeys.filter((item) => !aaa.includes(item));

      setCheckedKeys(result);
    } else if (!checked && !numberInArray(node.permissionId, parentID)) {
      // 单独取消子,父存在的情况下

      const result = checkedKeys.filter((item) => ![node.permissionId].includes(item));

      setCheckedKeys(result);
    } else if (checked && !numberInArray(node.permissionId, parentID)) {
      // 父被选中情况下,单独添加子

      if (selectedParents.length != 0) {
        const result = checkedNodes.map((item) => item.permissionId);

        const result1 = findParentPermissionIds(node.permissionId, treeData);
        const ccc = [result, node.permissionId, result1];

        // 使用concat和apply来将嵌套数组扁平化
        const flattenedArray = [].concat.apply([], ccc);

        // 使用Set来去重
        const uniqueArray = [...new Set(flattenedArray)];

        setCheckedKeys(uniqueArray);
      } else {
        // 父为空的情况下,单独添加子,让父也被选中

        const result = findParentPermissionIds(node.permissionId, treeData);

        const ccc = [result, node.permissionId];

        setCheckedKeys(ccc);
      }
    }
  };



<Tree
                checkable
                checkedKeys={checkedKeys}
                defaultExpandAll={false} //让授权后的弹窗只展示根标签
                treeData={treeData}  // 这里是所有的树形数据
                // showLine //删除这里,树形结构左侧的下拉线消失,图标从+-更改为默认的△
                checkStrictly // 开启后,父子节点不关联(子空一个,父就空)
                onCheck={ontreeCheck}
              />

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值