渲染出一棵树

Render out a tree

本文关键字:一棵树      更新时间:2023-09-26

我需要用javascript将带有关系的平面数据渲染成html树结构。我需要在没有任何图书馆帮助的情况下做这件事。数据本身是平坦的:

[
{id : 1, title : one, parent : null},
{id : 2, title : two, parent : 1},
{id : 3, title : three, parent : 2},
{id : 4, title : four, parent : null},
{id : 5, title : five, parent : 4},
{id : 6, title : six, parent : 4},
{id : 7, title : seven, parent : 6},
{id : 8, title : eight, parent : 7},
{id : 9, title : nine, parent : 8}
]

这就是想要的结果:

<div>one
  <div>two
    <div>three</div>
  </div>
</div>
<div>four
  <div>five</div>
  <div>six
    <div>seven
      <div>eight
        <div>nine
        </div>
      </div>
    </div>
  </div>
</div>

数据的深度是任意的(即,根据数据的不同,它可以是一级或一百级深)。

我一直在寻找答案,但大多数都指向库或使用嵌套的数据(在大多数情况下,这只会将嵌套问题推到服务器上)。

这里有一个递归函数,用于将对象数组(使用您的结构)转换为html字符串,表示div标记的层次结构。

function menuTree(nodes, parentId) {
    return nodes.reduce(function(html, node) {
        return html + (node.parent === parentId
            ? ''n<div>' + node.title + menuTree(nodes, node.id) + '</div>'
            : '');
    }, '');
}

你这样称呼它:

var nodes = [
    {"id": 1, "title": "one",   "parent": null},
    {"id": 2, "title": "two",   "parent": 1},
    {"id": 3, "title": "three", "parent": 2},
    {"id": 4, "title": "four",  "parent": null},
    {"id": 5, "title": "five",  "parent": 4},
    {"id": 6, "title": "six",   "parent": 4},
    {"id": 7, "title": "seven", "parent": 6},
    {"id": 8, "title": "eight", "parent": 7},
    {"id": 9, "title": "nine",  "parent": 8}
];
var html = menuTree(nodes, null);
console.log(html);

这里有一把小提琴,以交互方式演示了上面的内容。此fiddle允许您更改json描述并相应地复制div树。通过使用一些基本的css,对div树进行了缩进绘制。

成本为O(n)的迭代方法是

function makeTree(data) {
  var elements = Array(data.length + 1),
      proto = document.createElement('div');
  for(var i=0; i<=data.length; ++i)
    elements[i] = proto.cloneNode(false);
  for(var i=0; i<data.length; ++i) {
    var elem = elements[data[i].id];
    elements[+data[i].parent].appendChild(elem);
    elem.insertBefore(
      document.createTextNode(data[i].title),
      elem.firstChild
    );
  }
  return elements[0];
}

var data = [
  {id : 9, title : "nine", parent : 8},
  {id : 1, title : "one", parent : null},
  {id : 2, title : "two", parent : 1},
  {id : 3, title : "three", parent : 2},
  {id : 4, title : "four", parent : null},
  {id : 5, title : "five", parent : 4},
  {id : 6, title : "six", parent : 4},
  {id : 7, title : "seven", parent : 6},
  {id : 8, title : "eight", parent : 7}
];
function makeTree(data) {
  var elements = Array(data.length + 1),
      proto = document.createElement('div');
  for(var i=0; i<=data.length; ++i)
    elements[i] = proto.cloneNode(false);
  for(var i=0; i<data.length; ++i) {
    var elem = elements[data[i].id];
    elements[+data[i].parent].appendChild(elem);
    elem.insertBefore(
      document.createTextNode(data[i].title),
      elem.firstChild
    );
  }
  return elements[0];
}
document.body.appendChild(makeTree(data));
div {
  padding-left: 10px;
}

即使在定义元素的数据之前将其引用为父元素,上面的代码也会起作用。然而,它假设ID是从1到n的连续整数。如果它们可以是稀疏的或字符串,那么使用对象而不是数组。平均而言,它也将是O(n)。

var data = [
  {id : "id9", title : "nine", parent : "id8"},
  {id : "id1", title : "one", parent : null},
  {id : "id2", title : "two", parent : "id1"},
  {id : "id3", title : "three", parent : "id2"},
  {id : "id4", title : "four", parent : null},
  {id : "id5", title : "five", parent : "id4"},
  {id : "id6", title : "six", parent : "id4"},
  {id : "id7", title : "seven", parent : "id6"},
  {id : "id8", title : "eight", parent : "id7"}
];
function makeTree(data) {
  function getEl(id) {
    if(id === null) return wrapper;
    return elements[id] = elements[id] || wrapper.cloneNode(false);
  }
  var elements = {},
      wrapper = document.createElement('div');
  for(var i=0; i<data.length; ++i) {
    var el = getEl(data[i].id);
    getEl(data[i].parent).appendChild(el);
    el.insertBefore(
      document.createTextNode(data[i].title),
      el.firstChild
    );
  }
  return wrapper;
}
document.body.appendChild(makeTree(data));
div {
  padding-left: 10px;
}