zy-react-library/components/LeftTree/Basic/index.js

185 lines
4.9 KiB
JavaScript
Raw Normal View History

import { Input, Tree } from "antd";
import { useEffect, useState } from "react";
const { Search } = Input;
/**
* 基础左侧树组件不建议直接使用此组件二次继承使用
*/
const BasicLeftTree = (props) => {
const {
onSelect,
onGetNodePaths,
onGetNodePathsIsIncludeOneself = true,
expandedKeys: externalExpandedKeys,
treeData = [],
nameKey = "name",
idKey = "id",
childrenKey = "childrenList",
...restProps
} = props;
const [expandedKeys, setExpandedKeys] = useState([]);
const [searchValue, setSearchValue] = useState("");
const [autoExpandParent, setAutoExpandParent] = useState(true);
useEffect(() => {
setExpandedKeys(externalExpandedKeys);
}, [externalExpandedKeys]);
// 展开所有包含匹配项的父节点
const getAllExpandedKeys = (data, searchValue, keys = []) => {
data.forEach((node) => {
if (node[childrenKey]) {
if (node[nameKey].includes(searchValue)
|| node[childrenKey].some(child => child[nameKey].includes(searchValue))) {
keys.push(node[idKey]);
}
getAllExpandedKeys(node[childrenKey], searchValue, keys);
}
});
return keys;
};
// 过滤树数据,只保留匹配的节点
const filterTreeData = (data, searchValue) => {
if (!searchValue) {
return data;
}
return data.reduce((acc, node) => {
// 检查当前节点是否匹配
const isMatch = node[nameKey].includes(searchValue);
// 递归处理子节点
const filteredChildren = node[childrenKey] ? filterTreeData(node[childrenKey], searchValue) : [];
// 如果当前节点匹配或者有匹配的子节点,则保留该节点
if (isMatch || filteredChildren.length > 0) {
acc.push({
...node,
[childrenKey]: filteredChildren.length > 0 ? filteredChildren : undefined,
});
}
return acc;
}, []);
};
const handleExpand = (newExpandedKeys) => {
setExpandedKeys(newExpandedKeys);
setAutoExpandParent(false);
};
const getNodePaths = (data, targetId, idKey, childrenKey, path = [], isIncludeOneself) => {
for (let i = 0; i < data.length; i++) {
const node = data[i];
const newPath = [...path, node];
// 找到目标节点根据isIncludeOneself决定是否包含自身
if (node[idKey] === targetId) {
if (isIncludeOneself)
return newPath; // 包含自身
else
return path; // 不包含自身,只返回父节点路径
}
// 递归查找子节点
if (node[childrenKey] && node[childrenKey].length > 0) {
const result = getNodePaths(node[childrenKey], targetId, idKey, childrenKey, newPath, isIncludeOneself);
if (result) {
return result;
}
}
}
return null;
};
const handleSelect = (selectedKeys, event) => {
if (selectedKeys.length > 0) {
const selectedNodeId = selectedKeys[0];
const parentNodes = getNodePaths(treeData, selectedNodeId, idKey, childrenKey, onGetNodePathsIsIncludeOneself);
onGetNodePaths?.(parentNodes);
}
onSelect?.(selectedKeys, event);
};
const onFilterTreeData = (value) => {
setSearchValue(value);
setAutoExpandParent(true);
if (!value) {
setExpandedKeys([]);
return;
}
const expandedKeys = getAllExpandedKeys(treeData, value);
setExpandedKeys(expandedKeys);
};
const onSearch = async (value) => {
if (value === searchValue)
return;
onFilterTreeData(value);
};
// 渲染带高亮的标题
const renderTitle = (name) => {
if (!searchValue)
return name;
const index = name.indexOf(searchValue);
if (index === -1)
return name;
const beforeStr = name.substring(0, index);
const afterStr = name.substring(index + searchValue.length);
return (
<span>
{beforeStr}
<span style={{ color: "#f50" }}>{searchValue}</span>
{afterStr}
</span>
);
};
// 递归处理树节点标题显示
const processTreeData = (data) => {
return data.map(node => ({
...node,
[nameKey]: renderTitle(node[nameKey]),
[childrenKey]: node[childrenKey] ? processTreeData(node[childrenKey]) : undefined,
}));
};
// 过滤并处理树数据
const filteredTreeData = filterTreeData(treeData, searchValue);
const processedTreeData = processTreeData(filteredTreeData);
return (
<div style={{ width: 300 }}>
<Search
style={{ marginBottom: 8 }}
placeholder="输入关键字进行过滤"
onSearch={onSearch}
/>
<Tree
onExpand={handleExpand}
onSelect={handleSelect}
autoExpandParent={autoExpandParent}
expandedKeys={expandedKeys}
treeData={processedTreeData}
fieldNames={{ title: nameKey, key: idKey, children: childrenKey }}
{...restProps}
/>
</div>
);
};
BasicLeftTree.displayName = "BasicLeftTree";
export default BasicLeftTree;