一个前端,爱跑步、爱吉他、爱做饭、爱生活、爱编程、爱南芳姑娘,爱我所爱。世间最温暖又无价的是阳光、空气与爱,愿它们能带你去更远的地方。

  • 文章
  • 心情
  • 照片墙
  • 留言板
  • 工具
  • 友链
  • biaoblog

    专注web开发技术分享

    material Tree组件的前端模糊搜索

    技术 164 2022-11-04 16:06

    首先说下我们的需求:

    根据materialUI组件的treeView 来进行前端的模糊搜索

    展开所选节点所在的父节点,

    同时所匹配到的节点高亮显示


    思路:需要先把全部的树节点平铺到一层,

    然后根据所选择的子节点(这里场景是搜索,可以是多个子节点),


    循环遍历多个所选择的子节点,

    然后写一个递归函数,依次传递所选择节点的parsentid,

    去跟已经平铺到一层的全部节点进行对比,parsentid === id 则添加到父节点的数组中,

    然后再传递 已经匹配上的 全部节点中的 那一个节点 (因为父节点还可能拥有父节点),进行递归。


    具体的代码:

    import React from 'react';
    import { makeStyles } from '@material-ui/core/styles';
    import TreeView from '@material-ui/lab/TreeView';
    import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
    import ChevronRightIcon from '@material-ui/icons/ChevronRight';
    import TreeItem from '@material-ui/lab/TreeItem';
    
    const data = [
      {
        id: 93,
        label: 'USA',
        labelCn: 'USA',
        value: 93,
        children: [
          {
            id: 94,
            label: 'US Citizen',
            labelCn: 'US Citizen',
            value: 94,
            parentId: 93,
            checked: false,
          },
          {
            id: 95,
            label: 'Green Card',
            labelCn: 'Green Card',
            value: 95,
            parentId: 93,
            checked: false,
          },
          {
            id: 96,
            label: 'Working Visa',
            labelCn: 'Working Visa',
            value: 96,
            children: [
              {
                id: 97,
                label: 'H',
                labelCn: 'H',
                value: 97,
                parentId: 96,
                checked: false,
              },
              {
                id: 98,
                label: 'L',
                labelCn: 'L',
                value: 98,
                parentId: 96,
                checked: false,
              },
              {
                id: 99,
                label: 'O',
                labelCn: 'O',
                value: 99,
                parentId: 96,
                checked: false,
                children: null,
              },
              {
                id: 9999,
                label: 'WW',
                labelCn: 'WW',
                value: 9999,
                parentId: 96,
                checked: false,
                children: null,
              },
            ],
            parentId: 93,
            checked: false,
          },
          {
            id: 100,
            label: 'EAD Card',
            labelCn: 'EAD Card',
            value: 100,
            children: [
              {
                id: 101,
                label: 'OPT/STEM OPT',
                labelCn: 'OPT/STEM OPT',
                value: 101,
                parentId: 100,
                checked: false,
              },
              {
                id: 102,
                label: 'Asylum',
                labelCn: 'Asylum',
                value: 102,
                parentId: 100,
                checked: false,
              },
              {
                id: 103,
                label: 'H4-EAD',
                labelCn: 'H4-EAD',
                value: 103,
                parentId: 100,
                checked: false,
              },
              {
                id: 104,
                label: 'J2-EAD',
                labelCn: 'J2-EAD',
                value: 104,
                parentId: 100,
                checked: false,
              },
              {
                id: 105,
                label: 'L2-EAD',
                labelCn: 'L2-EAD',
                value: 105,
                parentId: 100,
                checked: false,
              },
              {
                id: 106,
                label: '485 EAD',
                labelCn: '485 EAD',
                value: 106,
                parentId: 100,
                checked: false,
              },
            ],
            parentId: 93,
            checked: false,
          },
        ],
        parentId: 0,
        checked: false,
      },
      {
        id: 107,
        label: 'Canada',
        labelCn: 'Canada',
        value: 107,
        children: [
          {
            id: 108,
            label: 'Canadian Citizen',
            labelCn: 'Canadian Citizen',
            value: 108,
            parentId: 107,
            checked: false,
          },
          {
            id: 109,
            label: 'Permanent Resident',
            labelCn: 'Permanent Resident',
            value: 109,
            parentId: 107,
            checked: false,
          },
          {
            id: 110,
            label: 'Open Work Permit',
            labelCn: 'Open Work Permit',
            value: 110,
            parentId: 107,
            checked: false,
          },
          {
            id: 111,
            label: 'Student Visa',
            labelCn: 'Student Visa',
            value: 111,
            parentId: 107,
            checked: false,
          },
        ],
        parentId: 0,
        checked: false,
      },
      {
        id: 112,
        label: 'Europe',
        labelCn: 'Europe',
        value: 112,
        children: [
          {
            id: 113,
            label: 'Citizen',
            labelCn: 'Citizen',
            value: 113,
            parentId: 112,
            checked: false,
          },
          {
            id: 114,
            label: 'Permanent Resident',
            labelCn: 'Permanent Resident',
            value: 114,
            parentId: 112,
            checked: false,
          },
          {
            id: 115,
            label: 'Work permit with restrictions',
            labelCn: 'Work permit with restrictions',
            value: 115,
            parentId: 112,
            checked: false,
          },
          {
            id: 116,
            label: 'Student Visa',
            labelCn: 'Student Visa',
            value: 116,
            parentId: 112,
            checked: false,
          },
        ],
        parentId: 0,
        checked: false,
      },
    ];
    
    const useStyles = makeStyles({
      root: {
        height: 110,
        flexGrow: 1,
        maxWidth: 400,
      },
    });
    
    export default function RecursiveTreeView() {
      const classes = useStyles();
      const [expanded, setExpanded] = React.useState([]);
      const [selected, setSelected] = React.useState([]);
    
      const setTreeLabel = (node) => {
        return (
          <div>
            <span>
              {node.label} - {node.id}
            </span>
          </div>
        );
      };
    
      const renderTree = (nodes) =>
        nodes.map((item, index) => {
          return (
            <TreeItem
              key={item.id}
              setChecked={(item) => {
                setChecked(item);
              }}
              nodeId={`${item.id}`}
              item={item}
              label={setTreeLabel(item)}
            >
              {item.children ? renderTree(item.children) : null}
            </TreeItem>
          );
        });
    
      const handleToggle = (event, nodeIds) => {
        setExpanded(nodeIds);
      };
    
      const handleSelect = (event, nodeIds) => {
        setSelected(nodeIds);
      };
    
      let timer = null;
    
      const search = (e) => {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
          let value = e.target.value;
          let expanded = [];
          let selected = [];
          if (value) {
            selected = findNodes(data, value, []);
            expanded = findParsent(selected);
          }
          setSelected(selected.map((n) => String(n.id)));
          setExpanded(expanded.map((n) => String(n.id)));
        }, 100);
      };
    
      const setSpreadTreeData = (tree, data = []) => {
        for (let i = 0; i < tree.length; i++) {
          let item = tree[i];
          data.push(item);
          item.children && setSpreadTreeData(item.children, data);
        }
        return data;
      };
    
      const findNodes = (data, value, arr) => {
        for (let node of data) {
          if (node.label.toUpperCase().includes(value.toUpperCase())) {
            arr.push(node);
          }
          if (node.children) {
            findNodes(node.children, value, arr);
          }
        }
        return arr;
      };
    
      const findParsent = (selected) => {
        let spreadTreeData = setSpreadTreeData(data);
        let parsentNodes = [];
        let dist = (parentId, arr) => {
          for (let s of spreadTreeData) {
            if (s.id == parentId) {
              arr.push(s);
              if (s.parentId) {
                dist(s.parentId, arr);
              }
            }
          }
          return arr;
        };
        for (let s of selected) {
          parsentNodes = dist(s.parentId, parsentNodes);
        }
        return parsentNodes;
      };
    
      return (
        <div>
          <input type="text" onChange={search} />
          <TreeView
            className={classes.root}
            defaultCollapseIcon={<ExpandMoreIcon />}
            defaultExpanded={['root']}
            defaultExpandIcon={<ChevronRightIcon />}
            expanded={expanded}
            selected={selected}
            onNodeToggle={handleToggle}
            multiSelect
            onNodeSelect={handleSelect}
          >
            {renderTree(data)}
          </TreeView>
        </div>
      );
    }
    


    效果图:

    文章评论

    评论列表(0