ant.design 組件庫(kù)中的 Tree 組件實(shí)現(xiàn)可搜索的樹(shù),在這里我會(huì)詳細(xì)介紹每個(gè)方法,以及容易踩坑的點(diǎn)。
效果圖:
首先是要導(dǎo)入的文件
// React 自帶的屬性
import React, { useMemo, useState } from 'react';
// antd 組件庫(kù)中的,輸入框和樹(shù)形控件
import { Input, Tree } from 'antd';
// ts
import type { DataNode } from 'antd/es/tree';
下面是要渲染在 Tree 上的的數(shù)據(jù),這是一個(gè)偽數(shù)據(jù),如果你在開(kāi)發(fā)時(shí)使用,直接修改給對(duì)應(yīng)的變量名,賦值即可
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: React.Key[] = [];
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);
這個(gè)方法是 Tree 組件提供的,用來(lái)篩選出要渲染的數(shù)據(jù),篩選應(yīng)該是優(yōu)化一些性能的,因?yàn)樵谀玫浇涌跀?shù)據(jù)時(shí),每一項(xiàng)都可能會(huì)有很多的數(shù)據(jù),而這一步是篩選出有用的值,過(guò)濾到其他,dataList 就是用來(lái)接收這個(gè)篩選后的數(shù)據(jù)的。
// 得到篩選后的值,根據(jù)當(dāng)前要渲染的內(nèi)容來(lái)篩選
const dataList: { key: React.Key; title: string }[] = [];
// 將篩選后的值,賦給 dataList
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);
觸發(fā)了搜索后
觸發(fā)了搜索后,會(huì)使用這個(gè)方法來(lái)對(duì)比兩個(gè)參數(shù)key 和 tree,得到符合條件的值
key:當(dāng)前搜索的值
tree:所有渲染的數(shù)據(jù)
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!;
};
現(xiàn)在進(jìn)入進(jìn)入組件內(nèi),處理邏輯,以下內(nèi)容都包裹在 App組件中
const App: React.FC = () => {}
export default App;
要使用到的可修改狀態(tài)的值
expandedKeys :(受控)展開(kāi)指定的樹(shù)節(jié)點(diǎn)
searchValue : 在觸發(fā)搜索時(shí),存儲(chǔ)當(dāng)期輸入的字段
autoExpandParent :是否自動(dòng)展開(kāi)父節(jié)點(diǎn),所以它的默認(rèn)值是布爾值
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
const [searchValue, setSearchValue] = useState('');
const [autoExpandParent, setAutoExpandParent] = useState(true);
每次樹(shù)狀圖變動(dòng),會(huì)更新 expandedKeys ,來(lái)做接下來(lái)的操作
onExpand :展開(kāi)/收起節(jié)點(diǎn)時(shí)觸發(fā)
const onExpand = (newExpandedKeys: React.Key[]) => {
setExpandedKeys(newExpandedKeys);
setAutoExpandParent(false);
};
處理函數(shù)`onChange
下面這段代碼是一個(gè)事件處理函數(shù)onChange
,它接收一個(gè)React.ChangeEvent<HTMLInputElement>
類(lèi)型的事件對(duì)象作為參數(shù)。這個(gè)事件函數(shù)通常用于處理輸入框的值變化事件。
在函數(shù)內(nèi)部,首先通過(guò)解構(gòu)賦值取出事件對(duì)象的value
屬性,即輸入框的當(dāng)前值。
然后,通過(guò)dataList
數(shù)組的map
方法遍歷每個(gè)元素,并根據(jù)元素的title
屬性是否包含輸入框的值來(lái)判斷是否展開(kāi)節(jié)點(diǎn)。如果包含,則調(diào)用getParentKey
函數(shù)獲取該節(jié)點(diǎn)的父節(jié)點(diǎn)的key
,否則返回null
。這個(gè)步驟用于更新展開(kāi)的節(jié)點(diǎn)。
接下來(lái),使用filter
方法對(duì)newExpandedKeys
數(shù)組進(jìn)行過(guò)濾,去除其中的null
值,并且去掉重復(fù)的元素,得到最終的展開(kāi)節(jié)點(diǎn)數(shù)組newExpandedKeys
。
調(diào)用setExpandedKeys
函數(shù)將最終的展開(kāi)節(jié)點(diǎn)數(shù)組更新到狀態(tài)中。
接著,通過(guò)setSearchValue
函數(shù)將輸入框的值更新到狀態(tài)中。
最后,調(diào)用setAutoExpandParent
函數(shù)將autoExpandParent
狀態(tài)設(shè)置為true
,表示父節(jié)點(diǎn)也會(huì)被自動(dòng)展開(kāi)。
這段代碼的作用是實(shí)現(xiàn)一個(gè)用于過(guò)濾和展開(kāi)樹(shù)節(jié)點(diǎn)的搜索功能。當(dāng)輸入框的值發(fā)生變化時(shí),根據(jù)輸入的值進(jìn)行過(guò)濾,找到匹配的節(jié)點(diǎn),并展開(kāi)它們的父節(jié)點(diǎn),同時(shí)更新輸入框的值和展開(kāi)節(jié)點(diǎn)的狀態(tài)。
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);
};
下面這段代碼使用了useMemo
鉤子來(lái)創(chuàng)建一個(gè)名為treeData
的變量。useMemo
的作用是在依賴(lài)項(xiàng)(這里是searchValue
)發(fā)生變化時(shí)執(zhí)行內(nèi)部的函數(shù),并將函數(shù)的返回值作為treeData
的值。
函數(shù)內(nèi)部定義了一個(gè)名為loop
的遞歸函數(shù),用于遍歷樹(shù)形結(jié)構(gòu)的數(shù)據(jù)data
。
在loop
函數(shù)中,首先將item.title
轉(zhuǎn)換為字符串類(lèi)型,并使用indexOf
方法查找searchValue
在字符串中的位置。
根據(jù)索引的結(jié)果,通過(guò)substring
和slice
方法將字符串分割成前后兩部分,然后構(gòu)建一個(gè)新的title
元素。如果搜索值在標(biāo)題中存在,使用<span>
元素將搜索值高亮顯示;如果不存在,則直接使用原始的標(biāo)題。
接著,判斷item
是否有子節(jié)點(diǎn)(item.children
),如果有,則遞歸調(diào)用loop
函數(shù)處理子節(jié)點(diǎn),并將返回的結(jié)果作為children
屬性的值。
最后,在每個(gè)節(jié)點(diǎn)的處理中,都會(huì)返回一個(gè)包含title
和key
屬性的對(duì)象。
最外層的useMemo
的返回值就是使用loop
函數(shù)處理defaultData
得到的結(jié)果,它代表了樹(shù)形結(jié)構(gòu)數(shù)據(jù)經(jīng)過(guò)搜索值過(guò)濾和處理后的新數(shù)據(jù)。
總而言之,這段代碼的作用是根據(jù)搜索值searchValue
對(duì)樹(shù)形結(jié)構(gòu)數(shù)據(jù)進(jìn)行過(guò)濾,并對(duì)匹配的節(jié)點(diǎn)標(biāo)題進(jìn)行處理,添加搜索值的高亮顯示。最后返回經(jīng)過(guò)處理后的新的樹(shù)形結(jié)構(gòu)數(shù)據(jù)treeData
。
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]);
組件的結(jié)構(gòu)
最后就是組件的結(jié)構(gòu)了,這段代碼中使用了 Search
組件,通過(guò) placeholder
屬性設(shè)置了一個(gè)提示文本 Search
,并通過(guò) onChange
屬性指定了一個(gè)事件處理函數(shù) onChange
來(lái)處理搜索框的值變化事件。這個(gè) onChange
函數(shù)通常用于更新?tīng)顟B(tài)或執(zhí)行其他邏輯,以響應(yīng)搜索框中輸入的值的變化。
總而言之,這段代碼創(chuàng)建了一個(gè)包含搜索框和樹(shù)形結(jié)構(gòu)的組件,并將搜索框的值變化和樹(shù)節(jié)點(diǎn)的展開(kāi)或折疊事件與相應(yīng)的事件處理函數(shù)關(guān)聯(lián)起來(lái)。
return (
<div>
<Search style={{ marginBottom: 8 }} placeholder="Search" onChange={onChange} />
<Tree
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
treeData={treeData}
/>
</div>
);
};
完整代碼:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-629740.html
import React, { useMemo, useState } from 'react';
import { Input, Tree } from 'antd';
import type { DataNode } from 'antd/es/tree';
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: React.Key[] = [];
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: React.Key[]) => {
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;
官網(wǎng)地址: 樹(shù)形控件 Tree - Ant Design文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-629740.html
到了這里,關(guān)于ant.design 組件庫(kù)中的 Tree 組件實(shí)現(xiàn)可搜索的樹(shù): React+and+ts的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!