Material UI - TreeView 数据结构

问题描述 投票:0回答:2

我想构建从服务器获取的数据,因此我可以使用

TreeView
中的
Material UI
组件:https://material-ui.com/api/tree-view/

我正在获取大量数据,因此我想在用户单击展开按钮时从服务器获取子节点。所以 当第一个节点展开时,HTTP 请求将发送到服务器,该服务器返回该节点的所有子节点。当另一个节点展开时,会获取该节点的子节点等。

在页面启动时,我想获取根节点及其子节点。返回的 JSON 看起来像这样:

{
 "division": {
 "id": "1234",
 "name": "Teest",
 "address": "Oslo"
 },
 "children": [
   {
    "id": "3321",
    "parentId": "1234",
    "name": "Marketing",
    "address": "homestreet"
   },
   {
    "id": "3323",
    "parentId": "1234",
    "name": "Development",
    "address": "homestreet"
   }
 ]
}

展开

Marketing
节点时,我想进行 HTTP 调用来获取该节点的子节点。所以我会得到这样的 JSON:

{
  "children": [
    {
      "id": "2212",
      "parentId": "3321",
      "name": "R&D",
      "address": "homestreet"
    },
    {
      "id": "4212",
      "parentId": "3321",
      "name": "Testing",
      "address": "homestreet"
    }
  ]
}

但是我对如何创建这样一个数据结构感到困惑,该数据结构稍后可以在我的

TreeView
组件中使用。我怎样才能创建这样的结构?

javascript reactjs material-ui
2个回答
3
投票

对于仍在寻找此问题解决方案的人,我最近使用

TreeView API
中的
selected
expanded 属性的组合解决了这个问题。请参阅此 Code Sandbox demo,了解如何异步加载新子项并在加载后展开其父项的示例。

import React from "react";
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";
import TreeNode from "./TreeNode";

const mockApiCall = async () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      const nextId = Math.ceil(Math.random() * 100);
      resolve([
        {
          id: `${nextId}`,
          name: `child-${nextId}`,
          children: []
        },
        {
          id: `${nextId + 1}`,
          name: `child-${nextId + 1}`,
          children: []
        }
      ]);
    }, Math.ceil(Math.random() * 1000));
  });
};

export default class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      expanded: [],
      selected: "1",
      tree: new TreeNode({
        id: "1",
        name: "src",
        children: []
      })
    };
  }

  handleChange = async (event, nodeId) => {
    const node = this.state.tree.search(nodeId);
    if (node && !node.children.length) {
      mockApiCall()
        .then((result) => {
          this.setState({ tree: this.state.tree.addChildren(result, nodeId) });
        })
        .catch((err) => console.error(err))
        .finally(() => {
          this.setState({
            selected: nodeId,
            expanded: [...this.state.expanded, nodeId]
          });
        });
    }
  };

  createItemsFromTree = (tree) => {
    if (tree.children.length) {
      return (
        <TreeItem key={tree.id} nodeId={tree.id} label={tree.name}>
          {tree.children.length > 0 &&
            tree.children.map((child) => this.createItemsFromTree(child))}
        </TreeItem>
      );
    }
    return <TreeItem key={tree.id} nodeId={tree.id} label={tree.name} />;
  };

  render() {
    return (
      <TreeView
        defaultCollapseIcon={<ExpandMoreIcon />}
        defaultExpandIcon={<ChevronRightIcon />}
        selected={this.state.selected}
        onNodeSelect={this.handleChange}
        expanded={this.state.expanded}
      >
        {this.createItemsFromTree(this.state.tree)}
      </TreeView>
    );
  }
}

0
投票
<div class="container-fluid">
    <div class="row mt-3">
        <div class="col-lg-8">
            <div class="card">
                <div class="card-body">
                    <div id="tree">
                        <div class="branch">
                            <div class="entry main-entry"><span class="drop"><p-dropdown [options]="logicGates"
                                        optionLabel="name" placeholder="Select" /></span>
                                <div class="branch">
                                    <div class="entry">
                                        <span class="drop">
                                            <div class="card sub-card p-2">
                                                <div class="row align-items-center">
                                                    <div class="col-lg-4">
                                                        <select name="" id="" class="form-select">
                                                            <option value="">Select Field</option>
                                                        </select>
                                                    </div>
                                                    <div class="col-lg-4">
                                                        <select name="" id="" class="form-select">
                                                            <option value="">Select Condition</option>
                                                        </select>
                                                    </div>
                                                    <div class="col-lg-3">
                                                        <input type="text" class="form-control"
                                                            placeholder="Field Text">
                                                    </div>
                                                    <div class="col-lg-1">
                                                        <button class="btn border-0"><i
                                                                class='bx bx-trash'></i></button>
                                                    </div>
                                                </div>
                                            </div>
                                        </span>
                                    </div>
                                    <div class="entry">
                                        <span class="drop">
                                            <div class="card sub-card p-2">
                                                <div class="row align-items-center">
                                                    <div class="col-lg-4">
                                                        <select name="" id="" class="form-select">
                                                            <option value="">Select Field</option>
                                                        </select>
                                                    </div>
                                                    <div class="col-lg-4">
                                                        <select name="" id="" class="form-select">
                                                            <option value="">Select Condition</option>
                                                        </select>
                                                    </div>
                                                    <div class="col-lg-3">
                                                        <input type="text" class="form-control"
                                                            placeholder="Field Text">
                                                    </div>
                                                    <div class="col-lg-1">
                                                        <button class="btn border-0"><i
                                                                class='bx bx-trash'></i></button>
                                                    </div>
                                                </div>
                                            </div>
                                        </span>
                                    </div>
                                </div>
                                <div class="margin">
                                    <a href="">+ Add Condition</a>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="card-footer">
                    <button class="btn border-0 btn_foot me-3">
                        <i class='bx bx-plus-circle'></i> Add Rule
                    </button>
                    <button class="btn border-0 btn_foot">
                        <i class='bx bx-folder-plus'></i> Add Inner Group
                    </button>
                </div>
            </div>
        </div>
    </div>
</div>

#tree {
  display: inline-block;
  padding: 10px;
  width: 100%;
}

#tree * {
  box-sizing: border-box;
}

#tree .branch {
  padding: 20px 0 5px 20px;
}

#tree .branch:not(:first-child) {
  margin-left: 170px;
}

#tree .branch:not(:first-child):after {
  content: "";
  width: 20px;
  border-top: 1px solid #ccc;
  position: absolute;
  left: 150px;
  top: 50%;
  margin-top: 1px;
}

.entry {
  position: relative;
  min-height: 100px;
  display: block;
}

.entry:before {
  content: "";
  height: 100%;
  border-left: 1px solid #ccc;
  position: absolute;
  left: -20px;
}

.entry:first-child:after {
  height: 10px;
  border-radius: 10px 0 0 0;
}

.entry:first-child:before {
  width: 10px;
  height: 50%;
  top: 50%;
  margin-top: 1px;
  border-radius: 10px 0 0 0;
}

.entry:after {
  content: "";
  width: 20px;
  transition: border 0.5s;
  border-top: 1px solid #ccc;
  position: absolute;
  left: -20px;
  top: 50%;
  margin-top: 1px;
}

.entry:last-child:before {
  width: 10px;
  height: 50%;
  border-radius: 0 0 0 10px;
}
.entry:last-child:after {
  height: 10px;
  border-top: none;
  transition: border 0.5s;
  border-bottom: 1px solid #ccc;
  border-radius: 0 0 0 10px;
  margin-top: -9px;
}

.entry:only-child:after {
  width: 10px;
  height: 0px;
  margin-top: 1px;
  border-radius: 0px;
}

.entry:only-child:before {
  display: none;
}

.entry span {
  border: 1px solid #ccc;
  display: block;
  min-width: 150px;
  padding: 5px 10px;
  line-height: 20px;
  text-align: center;
  position: absolute;
  left: 0;
  top: 50%;
  margin-top: -15px;
  color: #666;
  font-family: arial, verdana, tahoma;
  font-size: 14px;
  display: inline-block;
  border-radius: 5px;
  transition: all 0.5s;
}

// #tree .entry span:hover,
// #tree .entry span:hover + .branch .entry span {
//   background: #e6e6e6;
//   color: #000;
//   border-color: #a6a6a6;
// }

#tree .entry span:hover + .branch .entry::after,
#tree .entry span:hover + .branch .entry::before,
#tree .entry span:hover + .branch::before,
#tree .entry span:hover + .branch .branch::before {
  border-color: #a6a6a6;
}
::ng-deep {
  .p-dropdown {
    border-radius: 20px;
    width: 150px;
  }
  .p-inputtext {
    padding: 0.35rem 0.45rem;
    font-size: 14px;
  }
  .p-icon {
    width: 0.5rem;
    height: 0.5rem;
  }
  .p-dropdown-panel .p-dropdown-items {
    padding-left: 0rem;
    margin-bottom: 0rem;
  }
  .p-dropdown-panel .p-dropdown-items .p-dropdown-item {
    padding: 0.55rem 0.75rem;
    text-align: start;
  }
}

div.main-entry {
  .drop {
    border: 0px;
    padding: 0px;
  }
}

.margin {
  margin-left: 180px;
  a {
    text-decoration: none;
  }
}

button.btn_foot {
  background: #0367a51f;
  color: #0367a5;
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.