You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:42:48