前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >material Tree组件父节点联动改造

material Tree组件父节点联动改造

作者头像
biaoblog.cn 个人博客
发布2022-12-14 14:05:47
7680
发布2022-12-14 14:05:47
举报

先看效果图:

父节点联动的规则如下:

        第一种情况:全部子节点勾选,则父节点也勾选 即checked = true

        第二种情况:子节点全部取消勾选,则父节点取消勾选 即checked = false

        第三种情况:部分子节点勾选,则父节点也勾选 即checked = true

实现思路:

在之前的逻辑上 - 即点击某个节点 其子节点也全部自动勾选,

得到的一组数据之后,(不在之前的逻辑上直接设置关联的父节点,因为子节点是从上往下递归,而父节点需要至下而上的寻找)

单独写一个关联父节点的方法:

1.首先根据所勾选的节点,查找到它的全部父节点(可能父节点还有父节点所以需要递归)

两个参数,一个所勾选的节点(多个,单个),一个完整的tree数据

代码语言:javascript
复制
// 根据树子节点(单个,多个)寻找所有父节点
export const findParentNodes = (selected, tree) => {
  let spreadTreeData = setSpreadTreeData(tree, false, []);
  let parsentNodes = [];
  let deep = (parentId, parsentNodes) => {
    for (let tree of spreadTreeData) {
      if (tree.id == parentId) {
        parsentNodes.push(tree);
        if (tree.parentId) {
          deep(tree.parentId, parsentNodes);
        }
      }
    }
    return parsentNodes;
  };

  // autotemplate 组件传递的seleted是个array需要处理
  if (Array.isArray(selected)) {
    for (let selectedItem of selected) {
      parsentNodes = deep(selectedItem.parentId, parsentNodes);
    }
  } else {
    parsentNodes = deep(selected.parentId, parsentNodes);
  }

  return parsentNodes;
};

还需要一个平铺tree数据的方法:setSpreadTreeData

代码语言:javascript
复制
// 平铺tree
// 此函数的作用:拿到树结构后 进行树结构的渲染 同时需要把已经checked的数据 平铺到一层
// 主要是因为Autocomplete组件需要进行渲染 是个只有一层的array
// jugdeCheck 这个字段如果平铺不需要判断是否checked 就不需要传递
export const setSpreadTreeData = (tree, jugdeCheck, data = []) => {
  for (let i = 0; i < tree.length; i++) {
    let item = tree[i];
    if (jugdeCheck) {
      if (item.checked) {
        data.push(item);
      }
    } else {
      data.push(item);
    }
    item.children && setSpreadTreeData(item.children, jugdeCheck, data);
  }
  return data;
};

2.得到所勾选的子节点的全部父节点之后,再单独写一个方法,传递之前已经处理勾选逻辑的数据,

进行向上遍历。

代码语言:javascript
复制
// 根据所勾选的子节点 关联其父节点
export const cascaderParsent = (parsents, checked, tree) => {
  for (let i = 0; i < tree.length; i++) {
    let item = tree[i];
    for (let parsent of parsents) {
      // console.log('parsent::', parsent);
      if (parsent.id === item.id) {
        let { checkedNodes, activeNodeChildren } = setSpreadTreeDataCascader(
          parsent.children || []
        );
        // 第一种情况:全部子节点勾选,则父节点也勾选 即checked = true
        // 第二种情况:子节点全部取消勾选,则父节点取消勾选 即checked = false
        // 第三种情况:部分子节点勾选,则父节点也勾选 即checked = true
        // console.log('checkedNodes::', checkedNodes);
        // console.log('activeNodeChildren::', activeNodeChildren);
        if (checkedNodes.length === activeNodeChildren.length) {
          item.checked = true;
        } else if (checkedNodes.length === 0 && activeNodeChildren.length > 0) {
          item.checked = false;
        } else {
          item.checked = true;
        }
      }
    }

    if (item.children) {
      // 继续往子集找
      cascaderParsent(parsents, checked, item.children);
    }
  }

  return tree;
};

这里判断父节点是是勾选或者是不勾选的逻辑是根据:

1.父节点全部的子节点

2.父节点已激活的子节点

判断逻辑如下:

        第一种情况:全部子节点勾选,则父节点也勾选 即checked = true

        第二种情况:子节点全部取消勾选,则父节点取消勾选 即checked = false

        第三种情况:部分子节点勾选,则父节点也勾选 即checked = true

这里还有一个平铺的方法:setSpreadTreeDataCascader

也可以使用之前的setSpreadTreeData ,但是需要递归两次

像这样:

代码语言:javascript
复制
       // 全部节点 
     let activeNodeChildrenCount = setSpreadTreeData(node.children);
        //获取当前父节点当前所有激活的子节点
      let checkedNodes = setSpreadTreeData(node.children, true);

但是效率很低,理想的状态是一次递归就生成两种所需数据:

改造一下:

代码语言:javascript
复制
// tree联动平铺专用
export const setSpreadTreeDataCascader = (
  tree,
  checkedNodes = [], //已勾选的节点
  activeNodeChildren = [] //全部节点 - 包含已勾选和未勾选
) => {
  for (let i = 0; i < tree.length; i++) {
    let item = tree[i];
    if (item.checked) {
      checkedNodes.push(item);
    }
    activeNodeChildren.push(item);
    item.children &&
      setSpreadTreeDataCascader(
        item.children,
        checkedNodes,
        activeNodeChildren
      );
  }
  return { checkedNodes, activeNodeChildren };
};

然后取值就可以这样做了:

代码语言:javascript
复制
      let { checkedNodes, activeNodeChildren } = setSpreadTreeDataCascader(
        node.children || []
      );

然后就是material chekbox的ui

横杠的ui其实就是checkbox的indeterminate属性

判断就行即可(代码为递归的一部分,前置还有treeItem的自定义label):

判断ui的逻辑为:

       有子集的情况下:

       第一种情况:全部子节点勾选,则父节点也是勾选的样式1 即indeterminate = false

       第二种情况:子节点全部取消勾选,则父节点是勾选的样式1 即即indeterminate = false

       第三种情况:部分子节点勾选,则父节点是勾选的样式2 即indeterminate = true

代码语言:javascript
复制
    // 判断chekbox样式  - 优化方案
    let jugdeIndetermainte = (node) => {
      let { checkedNodes, activeNodeChildren } = setSpreadTreeDataCascader(
        node.children || []
      );
      // 有子集的情况下:
      // 第一种情况:全部子节点勾选,则父节点也是勾选的样式1 即indeterminate = false
      // 第二种情况:子节点全部取消勾选,则父节点是勾选的样式1 即即indeterminate = false
      // 第三种情况:部分子节点勾选,则父节点是勾选的样式2 即indeterminate = true
      // console.log('checkedNodes::', checkedNodes.length);
      // console.log('activeNodeChildren::', activeNodeChildren.length);
      if (
        checkedNodes.length === activeNodeChildren.length ||
        (checkedNodes.length === 0 && activeNodeChildren.length > 0)
      ) {
        return false;
      } else {
        return true;
      }
    };

    <Checkbox
          indeterminate={jugdeIndetermainte(node)}
          checked={node.checked}
          color="primary"
          onChange={(e) => {
          	//balabala
          }}
        />

然后没什么了

有疑问可以留言

拜拜 各位同学!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档