一个遍历查询树的工具类
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;