React.js结合Material-UI实现TreeView搜索过滤功能求助
实现Material-UI TreeView的关键词搜索功能
嘿,我来帮你搞定这个搜索功能!结合material-search-bar和TreeView的核心思路是递归过滤树结构数据,同时保留匹配节点的层级关系,这样搜索结果能正确显示父-子结构。下面是分步实现方案:
1. 安装依赖
首先确保你已经安装了material-ui-search-bar:
npm install material-ui-search-bar # 或者用yarn yarn add material-ui-search-bar
2. 核心:递归过滤树数据
我们需要写一个递归函数,遍历树的每个节点,判断节点名称是否匹配搜索词,或者它的子节点中存在匹配项(这样父节点会被保留,即使父节点名称不匹配)。
const filterTreeItems = (items, searchTerm) => { // 如果搜索词为空,返回全部数据 if (!searchTerm.trim()) return items; return items.reduce((acc, item) => { // 检查当前节点是否匹配(不区分大小写) const isMatch = item.name.toLowerCase().includes(searchTerm.toLowerCase()); // 递归过滤子节点 const filteredChildren = item.children ? filterTreeItems(item.children, searchTerm) : []; // 如果当前节点匹配,或者有匹配的子节点,就保留该节点 if (isMatch || filteredChildren.length > 0) { acc.push({ ...item, // 若当前节点不匹配但有匹配子节点,只保留匹配的子节点;若当前节点匹配,保留所有子节点 children: isMatch ? item.children : filteredChildren }); } return acc; }, []); };
3. 在App组件中集成搜索栏与状态管理
我们需要在App组件中维护搜索关键词和过滤后的树数据状态,然后把过滤后的数据传给TreeView:
import React, { Component } from 'react'; import TreeView from '@mui/lab/TreeView'; import TreeItem from '@mui/lab/TreeItem'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import SearchBar from 'material-ui-search-bar'; // 你的示例数据 const originalTreeData = [ { id: 1, name: "Item 1", children: [ { id: 2, name: "Subitem 1", children: [ { id: 3, name: "Misc 1", children: [ { id: 4, name: "Misc 2" } ] } ] }, { id: 5, name: "Subitem 2", children: [ { id: 6, name: "Misc 3" } ] } ] }, { id: 7, name: "Item 2", children: [ { id: 8, name: "Subitem 1", children: [ { id: 9, name: "Misc 1" } ] }, { id: 10, name: "Subitem 2", children: [ { id: 11, name: "Misc 4" }, { id: 12, name: "Misc 5" }, { id: 13, name: "Misc 6", children: [ { id: 14, name: "Misc 7" } ] } ] } ] } ]; const getTreeItemsFromData = treeItems => { return treeItems.map(treeItemData => { let children = undefined; if (treeItemData.children && treeItemData.children.length > 0) { children = getTreeItemsFromData(treeItemData.children); } // 注意:TreeItem的nodeId需要是字符串类型,所以把数字id转成字符串 return( <TreeItem key={treeItemData.id} nodeId={treeItemData.id.toString()} label={treeItemData.name} children={children}/> ); }); }; const DataTreeView = ({ treeItems }) => { return( <TreeView defaultCollapseIcon={<ExpandMoreIcon />} defaultExpandIcon={<ChevronRightIcon />} > {getTreeItemsFromData(treeItems)} </TreeView> ); }; class App extends Component { constructor(props) { super(props); this.state = { searchValue: '', searchedNodes: originalTreeData }; } handleSearch = (value) => { const filtered = filterTreeItems(originalTreeData, value); this.setState({ searchValue: value, searchedNodes: filtered }); }; handleCancelSearch = () => { this.setState({ searchValue: '', searchedNodes: originalTreeData }); }; render() { return ( <div className="App" style={{ padding: '20px', maxWidth: '400px' }}> <SearchBar value={this.state.searchValue} onChange={this.handleSearch} onCancelSearch={this.handleCancelSearch} placeholder="搜索节点名称..." style={{ marginBottom: '20px' }} /> <DataTreeView treeItems={this.state.searchedNodes} /> </div> ); } } export default App;
关键说明
- 递归过滤逻辑:既保证匹配的节点被显示,也会保留它的所有父节点(即使父节点名称不匹配),这样用户能看到匹配节点的层级位置;如果父节点匹配,会显示它的所有子节点。
- 不区分大小写:搜索时把节点名称和搜索词都转成小写,提升用户体验。
- 状态管理:通过
searchValue记录当前搜索关键词,searchedNodes存储过滤后的树数据,每次搜索或取消搜索时更新状态。
这样就能实现你想要的搜索功能啦!
内容的提问来源于stack exchange,提问作者stefano
相关产品推荐
相关产品推荐

