[英]How to traverse and render nested HTML from an materialized path array which represents nested tree?
I've an array which frontend React component received after AJAX call. 我有一个数组,在AJAX调用之后,前端React组件收到了一个数组。 This array is nothing but annotated list sent from backend which represents Django-Treebeard model data.
该数组不过是从后端发送的带注释的列表,该列表表示Django-Treebeard模型数据。 Annotated list is a materialized path tree which structures all nodes of nested tree in the form of flat array.
带注释的列表是物化路径树,它以平面数组的形式构造嵌套树的所有节点。
Below is the exact data available in front-end 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
}
}
];
The actual data tree in the back-end is: 后端中的实际数据树为:
Root
|_ Metrolink Trafford Depot: 700m
|_Bus Stand: 300
|_Restaurant and Bars:
|_Trafford Bar : 650m
|_ Café Hardrock: 1.5km
|_ Hospital:
|_ Seymour Grove Health Centre: 320m
I want to create nested div structure representing above hierarchy as below: 我想创建表示上面的层次结构的嵌套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>
I've tried recursion but failed miserably. 我尝试过递归,但失败了。 Not even close to what I intended.
甚至没有达到我的预期。 I tried to search third party solutions but they require completely different structure of data.
我尝试搜索第三方解决方案,但它们需要完全不同的数据结构。 I don't want to change structure of data in the backend.
我不想更改后端的数据结构。 It's another hell I just came out through.
这是我刚经历的另一个地狱。 In addition, I think materialized path tree is better suited for backend efficiency.
另外,我认为物化路径树更适合后端效率。
How can I write React component to generate above HTML structure from given data? 如何编写React组件以根据给定数据生成上述HTML结构?
You could first create a nested object structure from it, using the path
property (split it in chunks of 4 characters). 您可以首先使用
path
属性从中创建一个嵌套的对象结构(将其拆分为4个字符的块)。 Once you have that, you can use recursion to create the HTML elements: 一旦有了它,就可以使用递归来创建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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.