mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-05 05:28:20 +08:00
161 lines
3.7 KiB
Markdown
161 lines
3.7 KiB
Markdown
---
|
|
order: 4
|
|
title:
|
|
zh-CN: 可搜索
|
|
en-US: Searchable
|
|
---
|
|
|
|
## zh-CN
|
|
|
|
可搜索的树。
|
|
|
|
## en-US
|
|
|
|
Searchable Tree.
|
|
|
|
```tsx
|
|
import { Input, Tree } from 'antd';
|
|
import type { DataNode } from 'antd/es/tree';
|
|
import React, { useMemo, useState } from 'react';
|
|
|
|
const { Search } = Input;
|
|
|
|
const x = 3;
|
|
const y = 2;
|
|
const z = 1;
|
|
const defaultData: DataNode[] = [];
|
|
|
|
const generateData = (_level: number, _preKey?: React.Key, _tns?: DataNode[]) => {
|
|
const preKey = _preKey || '0';
|
|
const tns = _tns || defaultData;
|
|
|
|
const children = [];
|
|
for (let i = 0; i < x; i++) {
|
|
const key = `${preKey}-${i}`;
|
|
tns.push({ title: key, key });
|
|
if (i < y) {
|
|
children.push(key);
|
|
}
|
|
}
|
|
if (_level < 0) {
|
|
return tns;
|
|
}
|
|
const level = _level - 1;
|
|
children.forEach((key, index) => {
|
|
tns[index].children = [];
|
|
return generateData(level, key, tns[index].children);
|
|
});
|
|
};
|
|
generateData(z);
|
|
|
|
const dataList: { key: React.Key; title: string }[] = [];
|
|
const generateList = (data: DataNode[]) => {
|
|
for (let i = 0; i < data.length; i++) {
|
|
const node = data[i];
|
|
const { key } = node;
|
|
dataList.push({ key, title: key as string });
|
|
if (node.children) {
|
|
generateList(node.children);
|
|
}
|
|
}
|
|
};
|
|
generateList(defaultData);
|
|
|
|
const getParentKey = (key: React.Key, tree: DataNode[]): React.Key => {
|
|
let parentKey: React.Key;
|
|
for (let i = 0; i < tree.length; i++) {
|
|
const node = tree[i];
|
|
if (node.children) {
|
|
if (node.children.some(item => item.key === key)) {
|
|
parentKey = node.key;
|
|
} else if (getParentKey(key, node.children)) {
|
|
parentKey = getParentKey(key, node.children);
|
|
}
|
|
}
|
|
}
|
|
return parentKey!;
|
|
};
|
|
|
|
const App: React.FC = () => {
|
|
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
|
|
const [searchValue, setSearchValue] = useState('');
|
|
const [autoExpandParent, setAutoExpandParent] = useState(true);
|
|
|
|
const onExpand = (newExpandedKeys: string[]) => {
|
|
setExpandedKeys(newExpandedKeys);
|
|
setAutoExpandParent(false);
|
|
};
|
|
|
|
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const { value } = e.target;
|
|
const newExpandedKeys = dataList
|
|
.map(item => {
|
|
if (item.title.indexOf(value) > -1) {
|
|
return getParentKey(item.key, defaultData);
|
|
}
|
|
return null;
|
|
})
|
|
.filter((item, i, self) => item && self.indexOf(item) === i);
|
|
setExpandedKeys(newExpandedKeys as React.Key[]);
|
|
setSearchValue(value);
|
|
setAutoExpandParent(true);
|
|
};
|
|
|
|
const treeData = useMemo(() => {
|
|
const loop = (data: DataNode[]): DataNode[] =>
|
|
data.map(item => {
|
|
const strTitle = item.title as string;
|
|
const index = strTitle.indexOf(searchValue);
|
|
const beforeStr = strTitle.substring(0, index);
|
|
const afterStr = strTitle.slice(index + searchValue.length);
|
|
const title =
|
|
index > -1 ? (
|
|
<span>
|
|
{beforeStr}
|
|
<span className="site-tree-search-value">{searchValue}</span>
|
|
{afterStr}
|
|
</span>
|
|
) : (
|
|
<span>{strTitle}</span>
|
|
);
|
|
if (item.children) {
|
|
return { title, key: item.key, children: loop(item.children) };
|
|
}
|
|
|
|
return {
|
|
title,
|
|
key: item.key,
|
|
};
|
|
});
|
|
|
|
return loop(defaultData);
|
|
}, [searchValue]);
|
|
|
|
return (
|
|
<div>
|
|
<Search style={{ marginBottom: 8 }} placeholder="Search" onChange={onChange} />
|
|
<Tree
|
|
onExpand={onExpand}
|
|
expandedKeys={expandedKeys}
|
|
autoExpandParent={autoExpandParent}
|
|
treeData={treeData}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default App;
|
|
```
|
|
|
|
```css
|
|
.site-tree-search-value {
|
|
color: #f50;
|
|
}
|
|
```
|
|
|
|
<style>
|
|
[data-theme="dark"] .site-tree-search-value {
|
|
color: #d84a1b;
|
|
}
|
|
</style>
|