我正在使用一个对象数组递归地绘制一棵树。我能够调出具有所有展开折叠相关功能的树。我在某种程度上实现了跨树搜索的搜索功能。如果叶匹配,我显示所有扩展到该节点的节点。当搜索中间节点或根节点时,我应该显示折叠状态然后可以展开
但是当我搜索第一级或中间父节点时,搜索给了我 proepr 结果,但是当我尝试打开它的子节点时,它是空的。当我搜索任何父母时,图标似乎也被扩展了。
例如,当我搜索
Category1
时,树向我显示Category1
带有展开的图标(应该是折叠状态),并且当我尝试展开它的空白时。
当我搜索Applications
时,树显示从类别1到应用程序的正确层次结构,但应用程序将处于展开状态并且那里也没有显示子项。
有人能告诉我我在做什么错吗
沙箱:https://codesandbox.io/s/searching-c1m50i?file=/src/DrawnTree.jsx
到目前为止我试过的代码
import React, { useState } from "react";
import "./styles.css";
import { Node } from "./Node";
const DrawnTree = ({ treeData, currentActive, setCurrentActive }) => {
const [search, setSearch] = useState("");
const containsNodesWithTerm = (nodes, searchTerm) => {
const ids = [];
const _traverse = (nodes, searchTerm) => {
nodes.forEach((node) => {
if (node.name.toUpperCase().includes(searchTerm.toUpperCase())) {
ids.push(node.key);
}
if (node.nodes.length) {
_traverse(node.nodes, searchTerm);
}
});
};
_traverse(nodes, searchTerm);
return ids.length;
};
const filterNodes = (nodes, searchTerm = "") => {
const _filter = (nodes, searchTerm) => {
nodes.forEach((node) => {
if (
node.name.toUpperCase().includes(searchTerm.toUpperCase()) ||
containsNodesWithTerm(node.nodes, searchTerm)
) {
node.visible = true;
node.opened = true;
} else {
node.visible = false;
}
if (!searchTerm) {
node.opened = false;
}
if (node.nodes.length) {
_filter(node.nodes, searchTerm);
}
});
};
_filter(nodes, searchTerm);
return nodes;
};
const filteredTree = filterNodes(treeData, search);
return (
<div>
<input type="text" onChange={(e) => setSearch(e.target.value)} />
<div className="tree-list-section">
<div className="left-holder-bottom-list-section">
{filteredTree.map((node) => (
<Node
key={node.key}
node={node}
level={0}
currentActive={currentActive}
setCurrentActive={setCurrentActive}
/>
))}
</div>
</div>
</div>
);
};
export default DrawnTree;
import React, { useEffect, useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export const Node = ({ node, level, currentActive, setCurrentActive }) => {
const { name, key, nodes, visible, opened } = node;
const [isOpen, setIsOpen] = useState(opened);
const hasChildren = !!node?.nodes?.length;
const nodeType = level === 0 ? "node" : !hasChildren ? "leaf" : "group";
const activeClassName = currentActive === name ? "active" : "";
useEffect(() => {
setIsOpen(opened);
}, [opened]);
if (!visible) {
return null;
}
return (
<>
<div
className={`list-row level-${level} ${nodeType} ${activeClassName}`}
onClick={() => {
setIsOpen((open) => !open);
if (!hasChildren) {
setCurrentActive((prevName) => (!(prevName === name) ? name : ""));
}
}}
key={key}
>
<div
className="list-item-holder"
style={{ paddingLeft: `${level === 0 ? "16" : 40 * level}px` }}
>
{hasChildren && (
<div className="list-item-expander-holder">
<span
className={`expand-collapse-icon ${
isOpen ? "collapse" : "expand"
}`}
>
<span className="expand-icon">
<FontAwesomeIcon icon="caret-down" />
</span>
<span className="collapse-icon">
<FontAwesomeIcon icon="caret-right" />
</span>
</span>
</div>
)}
<div className="list-item-details-holder">{name}</div>
</div>
</div>
{isOpen && hasChildren && (
<div className="list-row-children">
{nodes.map((node) => (
<Node
key={node.key}
node={node}
level={level + 1}
currentActive={currentActive}
setCurrentActive={setCurrentActive}
/>
))}
</div>
)}
</>
);
};
那是因为当你找到关键词的时候,你并没有让孩子知道他们的父母匹配关键词的状态。我将你的递归函数修改为:
const filterNodes = (nodes, searchTerm = "") => {
const _filter = (nodes, searchTerm, isFound) => {
nodes.forEach((node) => {
let currentIsFound = false;
if (node.name.toUpperCase().includes(searchTerm.toUpperCase())) {
node.visible = true;
node.opened = false;
currentIsFound = true;
} else if (containsNodesWithTerm(node.nodes, searchTerm)
) {
node.visible = true;
node.opened = true;
} else if (isFound) {
node.visible = true;
node.opened = false;
} else {
node.visible = false;
}
if (!searchTerm) {
node.opened = false;
}
if (node.nodes.length) {
_filter(node.nodes, searchTerm, currentIsFound || isFound);
}
});
};
_filter(nodes, searchTerm, false);
return nodes;
};
分叉沙箱: