【问题标题】:Javascript Recursive function to build Tree用于构建树的 Javascript 递归函数
【发布时间】:2020-02-27 09:52:10
【问题描述】:

您好,我使用JavaScriptjQuery 作为客户端脚本。我对Recursive functions 有点陌生。我有一个如下的 JSON 数据,我尝试通过编写递归函数使用下面的 JSON 数据创建树结构,但我无法构建树结构。

var jsonData = { "$id": "45", "_children": [{ "$id": "46", "_children": [{ "$id": "47", "_children": [{ "$id": "48", "_children": [{ "$id": "49", "_children": null, "id": "Test1", "text": "Text1", "name": "name1", "parent": null, "root": { "$ref": "49" }, "depth": 0, "children": [] }], "id": "id1", "text": "text2", "name": "name2", "parent": null, "root": { "$ref": "48" }, "depth": 0, "children": [{ "$ref": "49" }] }], "id": "id3", "text": "text4", "name": "name4", "parent": null, "root": { "$ref": "47" }, "depth": 0, "children": [{ "$ref": "48" }] }, { "$id": "50", "_children": [{ "$id": "51", "_children": [{ "$id": "52", "_children": null, "id": "id6", "text": "text6", "name": "name6", "parent": null, "root": { "$ref": "52" }, "depth": 0, "children": [] }], "id": "id7", "text": "text7", "name": "name7", "parent": null, "root": { "$ref": "51" }, "depth": 0, "children": [{ "$ref": "52" }] }], "id": "id8", "text": "text8", "name": "name8", "parent": null, "root": { "$ref": "50" }, "depth": 0, "children": [{ "$ref": "51" }] }], "id": "id9", "text": "text9", "name": "name9", "parent": null, "root": { "$ref": "46" }, "depth": 0, "children": [{ "$ref": "47" }, { "$ref": "50" }] }, { "$id": "53", "_children": [{ "$id": "54", "_children": null, "id": "id10", "text": "text10", "name": "name10", "parent": null, "root": { "$ref": "54" }, "depth": 0, "children": [] }], "id": "id11", "text": "text11", "name": "name11", "parent": null, "root": { "$ref": "53" }, "depth": 0, "children": [{ "$ref": "54" }] }], "id": "0", "text": "0", "name": "", "parent": null, "root": { "$ref": "45" }, "depth": 0, "children": [{ "$ref": "46" }, { "$ref": "53" }] }

所需输出:

var treeNode = {
                    id: 101, // random
                    text: object.name,
                    icon: "fas fa-plus",
                    subNode: {
                        // id, text, icon and subNode of Children object
                        // recursive data,  So on.... 
                    }
                };

任何人都可以建议我或帮助我根据上述 JSON 数据编写 javascript 或 jQuery Recursive function,以便我可以构建树结构。我知道我在寻求帮助,因为我对递归函数的了解较少。

【问题讨论】:

  • 为什么要投反对票?请添加评论

标签: javascript jquery recursion treeview recursive-datastructures


【解决方案1】:

如果我们稍微抽象一下,就很容易编写一个通用的树形映射函数。然后我们可以提供两个回调函数:一个是查找输入的子节点,一个是根据输入和映射的子节点构建输出节点。事实证明,这样的函数非常简单:

const mapTree = (getChildren, transformNode) => (tree) =>
  transformNode (
    tree, 
    (getChildren (tree) || []) .map (mapTree (getChildren, transformNode))
  )

对于您的数据,getChildren 就是 (node) => node._children

而节点转换可能很简单:

const transformNode = (node, children) => 
  ({
    id: node.$id,         // or a randomizing call?
    text: node.name,
    icon: "fas fa-plus",  // is this really a fixed value?
    subNode: children
  })

把这些放在一起我们得到

const mapTree = (getChildren, transformNode) => (tree) =>
  transformNode (
    tree, 
    (getChildren (tree) || []) .map (mapTree (getChildren, transformNode))
  )

const kids = (node) => node._children

const transformNode = (node, children) => 
  ({
    id: node.$id,
    text: node.name,
    icon: "fas fa-plus",    
    subNode: children
  })

const myTransform = mapTree (kids, transformNode)

const jsonData = { "$id": "45", "_children": [{ "$id": "46", "_children": [{ "$id": "47", "_children": [{ "$id": "48", "_children": [{ "$id": "49", "_children": null, "id": "Test1", "text": "Text1", "name": "name1", "parent": null, "root": { "$ref": "49" }, "depth": 0, "children": [] }], "id": "id1", "text": "text2", "name": "name2", "parent": null, "root": { "$ref": "48" }, "depth": 0, "children": [{ "$ref": "49" }] }], "id": "id3", "text": "text4", "name": "name4", "parent": null, "root": { "$ref": "47" }, "depth": 0, "children": [{ "$ref": "48" }] }, { "$id": "50", "_children": [{ "$id": "51", "_children": [{ "$id": "52", "_children": null, "id": "id6", "text": "text6", "name": "name6", "parent": null, "root": { "$ref": "52" }, "depth": 0, "children": [] }], "id": "id7", "text": "text7", "name": "name7", "parent": null, "root": { "$ref": "51" }, "depth": 0, "children": [{ "$ref": "52" }] }], "id": "id8", "text": "text8", "name": "name8", "parent": null, "root": { "$ref": "50" }, "depth": 0, "children": [{ "$ref": "51" }] }], "id": "id9", "text": "text9", "name": "name9", "parent": null, "root": { "$ref": "46" }, "depth": 0, "children": [{ "$ref": "47" }, { "$ref": "50" }] }, { "$id": "53", "_children": [{ "$id": "54", "_children": null, "id": "id10", "text": "text10", "name": "name10", "parent": null, "root": { "$ref": "54" }, "depth": 0, "children": [] }], "id": "id11", "text": "text11", "name": "name11", "parent": null, "root": { "$ref": "53" }, "depth": 0, "children": [{ "$ref": "54" }] }], "id": "0", "text": "0", "name": "", "parent": null, "root": { "$ref": "45" }, "depth": 0, "children": [{ "$ref": "46" }, { "$ref": "53" }] }

console .log (myTransform (jsonData))

这与您请求的输出略有不同。你写了subNode: { ... },但我返回的是一个对象数组subNodes: [ ... ],因为我没有真正理解这里的普通对象。

此外,如果输入节点没有子节点,这将产生一个空的 subNodes 数组。如果您不想拥有subNodes 属性,则可以替换

    subNode: children

类似的东西

    ...(children .length ? {subNode: children} : {})

显然,您不需要命名的助手,可以使用如下匿名函数调用mapTree

const myTransform = mapTree (
  (node) => node._children, 
  (node, children) => 
    ({
      id: node.$id,
      text: node.name,
      icon: "fas fa-plus",    
      subNode: children
    })
)

这个mapTree 函数非常容易编写,因为我在编写它时不必考虑输出或输入格式的任何细节。但也许这种抽象对我没有帮助,除了这里我永远不会使用它。如果是这样,我可以通过直接插入硬编码的回调来简单地修改抽象版本。只需一点点操作,它就会变成这个版本:

const newTransform = (node) =>
  ({
    id: node.$id,
    text: node.name,
    icon: "fas fa-plus",    
    subNode: (node._children || []).map(newTransform)
  })

const jsonData = { "$id": "45", "_children": [{ "$id": "46", "_children": [{ "$id": "47", "_children": [{ "$id": "48", "_children": [{ "$id": "49", "_children": null, "id": "Test1", "text": "Text1", "name": "name1", "parent": null, "root": { "$ref": "49" }, "depth": 0, "children": [] }], "id": "id1", "text": "text2", "name": "name2", "parent": null, "root": { "$ref": "48" }, "depth": 0, "children": [{ "$ref": "49" }] }], "id": "id3", "text": "text4", "name": "name4", "parent": null, "root": { "$ref": "47" }, "depth": 0, "children": [{ "$ref": "48" }] }, { "$id": "50", "_children": [{ "$id": "51", "_children": [{ "$id": "52", "_children": null, "id": "id6", "text": "text6", "name": "name6", "parent": null, "root": { "$ref": "52" }, "depth": 0, "children": [] }], "id": "id7", "text": "text7", "name": "name7", "parent": null, "root": { "$ref": "51" }, "depth": 0, "children": [{ "$ref": "52" }] }], "id": "id8", "text": "text8", "name": "name8", "parent": null, "root": { "$ref": "50" }, "depth": 0, "children": [{ "$ref": "51" }] }], "id": "id9", "text": "text9", "name": "name9", "parent": null, "root": { "$ref": "46" }, "depth": 0, "children": [{ "$ref": "47" }, { "$ref": "50" }] }, { "$id": "53", "_children": [{ "$id": "54", "_children": null, "id": "id10", "text": "text10", "name": "name10", "parent": null, "root": { "$ref": "54" }, "depth": 0, "children": [] }], "id": "id11", "text": "text11", "name": "name11", "parent": null, "root": { "$ref": "53" }, "depth": 0, "children": [{ "$ref": "54" }] }], "id": "0", "text": "0", "name": "", "parent": null, "root": { "$ref": "45" }, "depth": 0, "children": [{ "$ref": "46" }, { "$ref": "53" }] }

console .log (newTransform (jsonData))

这里有一个重点。这个通用函数比我尝试写一些东西来直接转换你的格式要容易得多。虽然过早抽象存在危险,但它也可以提供显着的好处。我可能会选择只保留最后一个版本,但通用抽象简化了它的开发。

【讨论】:

    【解决方案2】:

    使用 json 数据模型可以是这样的

    <!doctype html>
    
    <html>
      <head>
        <link rel="stylesheet" href="lib/style.css">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
      </head>
    
      <body>
        <div id="myDiv"></div>
      </body>
      <script>
    
    var treeData={
       "Id":"10",
       "text":"Document Categories",
       "icon":"fas fa-plus",
       "subNode":
        [
          {
             "Id":"11",
             "text":"Pdf Documents",
             "icon":"fas fa-plus",
             "subNode":[
                {
                   "Id":"31",
                   "text":"Book Pdfs",
                   "icon":"fas fa-plus",
                    "subNode":[]
                },
                {
                   "Id":"32",
                   "text":"EPub",
                   "icon":"fas fa-plus",
                   "subNode":[
                      {
                         "Id":"20",
                         "text":"EBook Epubs1",
                         "icon":"fas fa-plus",
                         "subNode":[]
                      },
                      {
                         "Id":"30",
                         "text":"EBook Epubs2",
                         "icon":"fas fa-plus",
                         "subNode":[]
                      }
                   ]
                }
             ]
          },
          {
             "Id":"33",
             "text":"Text Documents",
             "icon":"fas fa-plus",
             "subNode":[
                {
                   "Id":"32",
                   "text":"Book Text",
                   "icon":"fas fa-plus",
                    "subNode":[]
                },
                {
                   "Id":"35",
                   "text":"Automatic Text",
                   "icon":"fas fa-plus",
                   "subNode":[]
                }
             ]
          }
       ]
    };
    
        var newTree = AddRecursive(null, treeData);
        var treeDiv = $('#myDiv');
        treeDiv.append(newTree);
    
    
    function AddRecursive(tree, data) {
      if (tree == null) {
        tree = $('<ul/>');
        tree.attr('id', 'treeID');
      }
    
      var listU = $('<ul />');
      listU.addClass('ul class');
    
      var listItem = $('<li />');
      listItem.addClass('li class');
      listItem.attr('data-id', data.Id);
    
      var link = $('<a />');
      var i = $('<i/>').addClass('fa fa-folder');
      link.append(i);
    
      //link.addClass("linkClass");
      link.append(data.text);
      listItem.append(link);
    
      if (data.subNode.length > 0) {
        var span = $(' <span />');
        span.addClass('fa-chevron-down');
        link.append(span);
      }
    
      listU.append(listItem);
      tree.append(listU);
    
      for (i in data.subNode) {
        AddRecursive(listItem, data.subNode[i]);
      }
      return tree;
    }
    
    
    
      </script>
    </html>

    【讨论】:

    • 这件事有什么问题?你的目标是什么?你做了什么?请详细写出您在问题中的意图。
    猜你喜欢
    • 1970-01-01
    • 2019-04-14
    • 2011-11-25
    • 2021-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-18
    相关资源
    最近更新 更多