react树遍历方法

一个遍历查询树的工具类

export default class TreeUtil {
  static forEach = (treeData, callback, childrenKey = "children") => {
    const mapTree = (treeData, indexArr, parent) => {
      treeData.forEach((item, index) => {
        callback(item, [...indexArr, index], parent);
        if (item[childrenKey] && item[childrenKey].length > 0) {
          mapTree(item[childrenKey], [...indexArr, index], item);
        }
      });
    };
    mapTree(treeData, [], undefined);
  };

  static map = (
    treeData = [],
    callback = () => null,
    childrenKey = 'children',
  ) => {
    const mapTree = (treeData, indexArr, parent) => {
      return treeData.map((item, index) => {
        const _indexArr = [...indexArr, index];
        const c = callback(item, _indexArr, parent);

        if (item[childrenKey] && item[childrenKey].length) {
          c[childrenKey] = mapTree(item[childrenKey], _indexArr, item);
        }

        if (typeof c !== 'undefined') return c;
      });
    };

    return mapTree(treeData, [], undefined);
  };

  static some = (treeData, callback, childrenKey) => {
    return !!TreeUtil.find(treeData, callback, childrenKey);
  };

  static every = (treeData, callback, childrenKey) => {
    const mapTree = (treeData, indexArr, parent) => {
      for (let index = 0; index < treeData.length; index++) {
        const item = treeData[index];
        const _indexArr = [...indexArr, index];
        const isRight = callback(item, _indexArr, parent);

        if (!isRight) {
          return false;
        }
        if (item[childrenKey] && item[childrenKey].length) {
          mapTree(item[childrenKey], _indexArr, item);
        }
      }

      return true;
    };
    return mapTree(treeData, [], undefined);
  };

  static find = (treeData, callback, childrenKey = "children") => {
    const mapTree = (treeData, indexArr, parent) => {
      for (let index = 0; index < treeData.length; index++) {
        const item = treeData[index];
        const _indexArr = [...indexArr, index];
        const isRight = callback(item, _indexArr, parent);
        if (isRight) {
          return item;
        }
        if (item[childrenKey] && item[childrenKey].length) {
         return mapTree(item[childrenKey], _indexArr, item);
        }
      }
    };
    return mapTree(treeData, [], undefined);
  };

  // 树叶往树杆遍历
  static mapIndexArrReverse = (
    treeData,
    indexArr,
    callback = () => null,
    childrenKey = "children"
  ) => {
    for (let i = indexArr.length - 1; i > 0; i--) {
      let parent = treeData[indexArr[0]];

      // j=1:深度大于1才有父级;
      // j<i:i为当前深度,当前深度的前一个就是父级
      for (let j = 1; j < i; j++) {
        parent = parent[childrenKey][indexArr[j]];
      }
      callback(parent, i - 1);
    }
  };

  // 树干往树枝遍历
  static mapIndexArr = (
    treeData,
    indexArr,
    callback,
    childrenKey = "children"
  ) => {
    let parent = treeData;
    for (let i = 0; i < indexArr.length; i++) {
      parent = parent[indexArr[i]];
      callback(parent, i);
      parent = parent[childrenKey];
    }
  };
}

基于该工具类做出的树选择器demo

在这里插入图片描述

import React, { Component } from "react";
import TreeUtil from "../util/Tree";
const statusColor = {
  0: "#fff",
  1: "#333",
  2: "#999",
};
const switchStatusMap = {
  0: 1,
  1: 2,
  2: 0,
};
const Checkbox = ({ status = 0, onChange = () => null }) => {
  return (
    <div
      onClick={onChange}
      style={{
        height: "14px",
        width: "14px",
        display: "inline-flex",
        justifyContent: "center",
        alignItems: "center",
        border: "1px solid #999",
        marginRight: "8px",
        boxSizing: "border-box",
      }}
    >
      <div
        style={{
          height: "10px",
          width: "10px",
          backgroundColor: statusColor[status],
        }}
      />
    </div>
  );
};

class Tree extends Component {
  constructor(props) {
    super(props);
  }

  getTree = (treeData) => {
    return TreeUtil.map(treeData, (item, indexArr, parent) => {
      return (
        <div key={item.name} style={{ marginLeft: indexArr.length * 20 }}>
          <Checkbox
            status={item.check_status}
            onChange={() => {
              item.check_status = item.check_status === 1 ? 0 : 1;
              if (item.children?.length) {
                TreeUtil.forEach(item.children, (v) => {
                  v.check_status = item.check_status;
                });
              }
              if (indexArr.length > 1) {
                TreeUtil.mapIndexArrReverse(treeData, indexArr, (v) => {
                  const checkedList = [];
                  const isGrade= false;

                  v.children.forEach((n) => {
                    if (n.check_status === 1) {
                      checkedList.push(n.name);
                    }
                     if (n.check_status === 1 || n.check_status === 2) {
                      isGrade = true;
                    }
                  });

                  if (checkedList.length === v.children.length) {
                    v.check_status = 1;
                  } else if (isGrade) {
                    v.check_status = 2;
                  } else {
                    v.check_status = 0;
                  }
                });
              }

              this.forceUpdate();
            }}
          />
          {item.name}
        </div>
      );
    });
  };

  render() {
    const element = this.getTree(this.props.treeData);
    return <div>{element}</div>;
  }
}

export default Tree;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值