如何从平面JavaScript数组创建分层HTML结构
How to create hierarchical HTML structure from flat JavaScript array?
我被要求使用带有父ID的分层系统创建一个股票列表。我无法在父母的带领下展示孩子。我知道我需要使用某种递归函数,但我的大脑就是不让我弄清楚它如何组合在一起以适应无限量的缩进。
示例 JavaScript 数据...
[
{id: 1, parent_id: null, title: "Row 1"},
{id: 2, parent_id: 1, title: "Row 2"},
{id: 3, parent_id: 2, title: "Row 3"},
{id: 4, parent_id: 2, title: "Row 4"}
]
HTML 应该看起来像...
- 第 1 行
- 第 2 行
- 第 3 行
- 第 4 排
- 第 2 行
如果有人可以帮助我,那就太棒了,因为我已经被困在上面将近 4 个小时了,我找不到任何与我的特定目标相关的内容。
注意:这要求数据按父节点在子节点引用之前显示的方式排序。如果需要,可以先进行
sort
。编辑:下面发布了无排序的解决方案
这里有一种方法可以使用Array.prototype.reduce来做到这一点。
var arr = [
{id: 1, parent_id: null, title: "Row 1"},
{id: 2, parent_id: 1, title: "Row 2"},
{id: 3, parent_id: 2, title: "Row 3"},
{id: 4, parent_id: 2, title: "Row 4"}
];
var x = arr.reduce(function(map, node) {
map.i[node.id] = node;
node.children = [];
node.parent_id === null ?
map.result.push(node) :
map.i[node.parent_id].children.push(node);
return map;
}, {i:{}, result:[]}).result;
解释。我将逐步完成我使用的归约过程
使用
{i:{}, result:[]}
初始化化简我们将使用
i
对象作为引用父节点的方法,并使用result
数组来存储顶级根节点使用
map.i[node.id] = node
通过id
为每个节点编制索引如果节点是根节点 (
parent_id === null
),则将其添加到结果中,并带有map.result.push(node)
如果节点是子节点 (
parent_id !== null
),则使用map.index[node.parent_id].children.push(node)
将其添加到父节点的子数组中
好的,让我们检查一下它是否有效
// all root nodes
// see output below
console.log(JSON.stringify(x, null, " "));
// first "root" node
console.log(x[0].id); //=> 1
// first child of first root node
console.log(x[0].children[0].id); //=> 2
// first child of first child of first root node
console.log(x[0].children[0].children[0].id); //=> 3
// second child of first child of first root node
console.log(x[0].children[0].children[1].id); //=> 4
所有根节点输出
[
{
"id": 1,
"parent_id": null,
"title": "Row 1",
"children": [
{
"id": 2,
"parent_id": 1,
"title": "Row 2",
"children": [
{
"id": 3,
"parent_id": 2,
"title": "Row 3",
"children": []
},
{
"id": 4,
"parent_id": 2,
"title": "Row 4",
"children": []
}
]
}
]
}
]
<小时 />如果您的初始数据未排序...
在这种情况下,reduce
方法有点困难。诚然,这个解决方案几乎失去了所有的优雅,但我提供了它来表明它仍然是可能的。
// this works on arbitrarily sorted data
var x = arr.reduce(function(map, node) {
map.i[node.id] = node;
node.children = [];
if (node.parent_id === null) {
map.result.push(node);
}
else if (node.parent_id in map.i) {
map.i[node.parent_id].children.push(node);
}
else {
(node.parent_id in map.cache) ?
map.cache[node.parent_id].push(node) :
map.cache[node.parent_id] = [node];
}
if (node.id in map.cache) {
node.children = node.children.concat(map.cache[node.id]);
delete map.cache[node.id];
}
return map;
}, {i:{}, cache:{}, result:[]}).result;
受 Naomik 的启发,当 parent_id
不在正确的位置时,代码将失败。添加了一个排序功能,可以按正确的顺序设置它们。
obj = [
{id: 2, parent_id: 1, title: "Row 2"},
{id: 3, parent_id: 2, title: "Row 3"},
{id: 4, parent_id: 2, title: "Row 4"},
{id: 1, parent_id: null, title: "Row 1"}
]
obj.sort(function(a, b){
return (a.parent_id == null ? 0 : a.parent_id) - (b.parent_id == null ? 0 : b.parent_id);
});
var tree = document.getElementById("tree");
for (var i = 0; i < obj.length; ++i)
{
if (obj[i].parent_id == null)
{
createTreeElement("li", obj[i].id, obj[i].title, tree);
}
else
{
var treeChildNode = document.getElementById("t" + obj[i].parent_id).getElementsByTagName("ul");
if (treeChildNode.length)
{
createTreeElement("li", obj[i].id, obj[i].title, treeChildNode[0]);
}
else
{
createTreeElement("ul", obj[i].parentId, "", document.getElementById("t" + obj[i].parent_id));
createTreeElement("li", obj[i].id, obj[i].title, document.getElementById("t" + obj[i].parent_id).getElementsByTagName("ul")[0]);
}
}
}
function createTreeElement(name, id, text, parent)
{
var node = document.createElement(name);
node.id = "t" + id;
node.innerHTML = text;
parent.appendChild(node);
}
<ul id="tree">
</ul>
这段代码只是HTML中的概念证明,@Daniel Weiners根据对象模型回答为什么这里不需要递归。
您使用跟踪 id 的对象。例如:
var idObj = {};
var root = null;
// first populate the object with elements
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
idObj[item.id] = item;
}
// then attach the children to the parents
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
var parent = idObj[item.parent_id];
if (parent) {
parent.children = parent.children || [];
parent.children.push(item);
} else if (item.parent_id === null) {
//set the item as root if it has no parents
root = item;
}
}
这将向所有这些项添加一个 children
属性。
注意:此解决方案不是递归的,但您可以从root
变量开始递归遍历树。
- 创建一个类似链接的按钮,并通过Javascript函数打开一个新的弹出窗口
- 为effect Composer创建GodRays效果过程
- 从javascript创建一个列表
- onkeyup无法动态创建多个文本区域
- 如何使用javascript从主svg对象动态创建svg视图框
- 如何访问声音管理器2创建的声音对象
- 我已经创建了一个jquery转盘,并使用if条件来运行和停止转盘
- Kendo:我该如何在树视图中创建一个递归的hieiarchy
- 使用Facebook live API创建实时视频对象时的隐私设置
- 在动态创建的元素上获取对特定选择器的引用
- 如何创建带有插槽的vue js组件预加载程序
- 如何在创建键时引用来自同一对象的键
- 分层在Javascript中动态创建画布
- 如何在 d3.js 中创建分层条形图
- 如何在动态创建html时实现分层标题组织
- 在 NodeJS 中使用 Javascript 创建分层 PDF
- AngularJS :如何创建DOM并绑定到基于任意分层数据的模型
- 如何从平面JavaScript数组创建分层HTML结构
- 如何创建和使用动态分层JSON
- 为分层图像创建可设置动画的放射状遮罩