【问题标题】:How to traverse and render nested HTML from an materialized path array which represents nested tree?如何从表示嵌套树的物化路径数组中遍历和呈现嵌套 HTML?
【发布时间】:2019-07-12 12:48:33
【问题描述】:

我有一个数组,前端 React 组件在 AJAX 调用后收到。这个数组只不过是从后端发送的带注释的列表,它代表 Django-Treebeard 模型数据。 Annotated list是一个物化路径树,它以平面数组的形式将嵌套树的所有节点结构化。

以下是前端 react 中可用的确切数据:

const data = [
  {
    info: { close: [], open: true, level: 1 },
    spot: {
      id: 2,
      path: "00020002",
      depth: 2,
      numchild: 0,
      landmark_name: "Metrolink Trafford Depot",
      distance: "700.00",
      unit: "m",
      child: 0
    }
  },
  {
    info: { close: [], open: false, level: 1 },
    spot: {
      id: 3,
      path: "00020003",
      depth: 2,
      numchild: 0,
      landmark_name: "Bus Stand",
      distance: "300.00",
      unit: "m",
      child: 0
    }
  },
  {
    info: { close: [], open: false, level: 1 },
    spot: {
      id: 4,
      path: "00020005",
      depth: 2,
      numchild: 2,
      landmark_name: "Restaurants and Bars",
      distance: null,
      unit: null,
      child: 1
    }
  },
  {
    info: { close: [], open: true, level: 2 },
    spot: {
      id: 5,
      path: "000200050001",
      depth: 3,
      numchild: 2,
      landmark_name: "Trafford Bar",
      distance: 650.00,
      unit: "m",
      child: 1
    }
  },
  {
    info: { close: ["0"], open: false, level: 2 },
    spot: {
      id: 6,
      path: "000200050003",
      depth: 3,
      numchild: 0,
      landmark_name: "Café Hardrock",
      distance: "1.50 ",
      unit: "km",
      child: 0
    }
  },
  {
    info: { close: [], open: false, level: 1 },
    spot: {
      id: 8,
      path: "00020008",
      depth: 2,
      numchild: 1,
      landmark_name: "Hospital",
      distance: null,
      unit: null,
      child: 1
    }
  },
  {
    info: { close: ["0", "1", "2"], open: true, level: 2 },
    spot: {
      id: 14,
      path: "000200080001",
      depth: 3,
      numchild: 0,
      landmark_name: "Seymour Grove Health Centre",
      distance: "320.00",
      unit: "m",
      child: 0
    }
  }
];

后端的实际数据树是:

Root
|_ Metrolink Trafford Depot: 700m
|_Bus Stand: 300 
|_Restaurant and Bars:
  |_Trafford Bar : 650m
  |_ Café Hardrock: 1.5km
|_ Hospital:
  |_ Seymour Grove Health Centre: 320m

我想创建嵌套的 div 结构来表示上面的层次结构,如下所示:

<div>
    <h3> MetroLink Trafford Depot :</h3>
    <p> 700m </p>
</div>
<div>
    <h3> Bus Stand:</h3>
    <p>300m </p>
</div>
<div>
    <h3> Restaurants and Bars:</h3>
        <div>
            <h4> Trafford Bar:</h4>
            <p> 650m</p>
        </div>
        <div>
            <h4> Café Hardrock:</h4>
            <p> 1.5km</p>
        </div>
</div>
<div>
    <h3> Hospital:</h3>
        <div> 
            <h4> Seymour Grove Health Centre:</h4>
            <p>320m</p>
        </div>
</div>

我尝试过递归,但惨遭失败。甚至没有接近我的意图。 我试图搜索第三方解决方案,但它们需要完全不同的数据结构。我不想改变后端的数据结构。这是我刚出来的另一个地狱。另外,我认为物化路径树更适合后端效率。

如何编写 React 组件以根据给定数据生成上述 HTML 结构?

【问题讨论】:

  • 所以如果它是 1 级。创建一个新的 div。转到下一个数据,如果它是 2 级附加到该 div,同时删除段落等等?

标签: javascript reactjs tree nested jsx


【解决方案1】:

您可以首先使用path 属性从它创建一个嵌套对象结构(将其分成4 个字符的块)。一旦你有了它,你就可以使用递归来创建 HTML 元素:

class Tree extends React.Component {
    constructor(props) {
        super(props);
        this.state = { data: props.data }
    }
    render() {
        // Create nested tree structure from data
        let root = { children: {} };
        for (let {spot} of this.state.data) {
            let node = root;
            for (let child of spot.path.match(/..../g)) {
                if (!(child in node.children)) node.children[child] = { children: {} };
                node = node.children[child];
            }
            node.name = spot.landmark_name;
            if (spot.distance) node.distance = String(+spot.distance) + spot.unit;
        }
        // Create elements from tree
        const e = React.createElement;
        return (function recur(node, level=1) {
            let children = Object.values(node.children).map(child => recur(child, level+1));
            if (children.length === 1 && !node.name) return children[0];
            if (!children.length) children = [e("p", null, node.distance)];
            if (node.name) children.unshift(e("h" + level, null, node.name));
            return e("div", null, ...children);
        })(root);
    }
}

// Sample data from the question:
const data = [{info: { close: [], open: true, level: 1 },spot: {id: 2,path: "00020002",depth: 2,numchild: 0,landmark_name: "Metrolink Trafford Depot",distance: "700.00",unit: "m",child: 0}},{info: { close: [], open: false, level: 1 },spot: {id: 3,path: "00020003",depth: 2,numchild: 0,landmark_name: "Bus Stand",distance: "300.00",unit: "m",child: 0}},{info: { close: [], open: false, level: 1 },spot: {id: 4,path: "00020005",depth: 2,numchild: 2,landmark_name: "Restaurants and Bars",distance: null,unit: null,child: 1}},{info: { close: [], open: true, level: 2 },spot: {id: 5,path: "000200050001",depth: 3,numchild: 2,landmark_name: "Trafford Bar",distance: 650.00,unit: "m",child: 1}},{info: { close: ["0"], open: false, level: 2 },spot: {id: 6,path: "000200050003",depth: 3,numchild: 0,landmark_name: "Café Hardrock",distance: "1.50 ",unit: "km",child: 0}},{info: { close: [], open: false, level: 1 },spot: {id: 8,path: "00020008",depth: 2,numchild: 1,landmark_name: "Hospital",distance: null,unit: null,child: 1}},{info: { close: ["0", "1", "2"], open: true, level: 2 },spot: {id: 14,path: "000200080001",depth: 3,numchild: 0,landmark_name: "Seymour Grove Health Centre",distance: "320.00",unit: "m",child: 0}}];

// Render
ReactDOM.render(React.createElement(Tree, {data}), document.body);
div, p { margin-left: 20px }
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-13
    • 2021-08-18
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-14
    • 2021-06-16
    相关资源
    最近更新 更多