简体   繁体   English

Javascript 递归 function 构建树

[英]Javascript Recursive function to build Tree

Hi I am using JavaScript and jQuery as client side script.嗨,我使用JavaScriptjQuery作为客户端脚本。 I am little bit new to Recursive functions .我对Recursive functions有点陌生。 I have a JSON data as below and I have tried to make a tree structure using below JSON data by writing a recursive function but I am not able to build the tree structure.我有一个 JSON 数据,如下所示,我尝试通过编写递归 function 数据来使用 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" }] }

Required Output:所需 Output:

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.... 
                    }
                };

Can anyone suggest me or help me to write javascript or jQuery Recursive function based on above JSON data so I can build tree structure.谁能建议我或帮我写 javascript 或 jQuery Recursive function基于上述 Z0ECD11C1D7A23BB87401D8ZD 数据,所以可以构建树结构。 I know I am asking about help because I do have less knowledge about recursive function.我知道我在寻求帮助,因为我对递归 function 的了解较少。

If we abstract this a bit, it's pretty easy to write a general-purpose tree-mapping function.如果我们稍微抽象一下,就很容易编写通用的树形映射 function。 Then we can supply two callback functions: one to find the child nodes of the input and one to build the output node based on the input and the mapped children.然后我们可以提供两个回调函数:一个找到输入的子节点,一个根据输入和映射的子节点构建 output 节点。 Such a function turns out to be surprisingly simple:这样的 function 结果出奇地简单:

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

For your data, getChildren is simply (node) => node._children对于您的数据, getChildren只是(node) => node._children

And the node transformation might be as simple as:节点转换可能很简单:

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
  })

Putting this together we get把它放在一起,我们得到

 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))

This does something slightly different from your requested output.这与您请求的 output 略有不同。 You had written subNode: {... } , but instead I'm returning an array of objects, subNodes: [... ] , as I don't make any real sense of a plain object here.您已经编写subNode: {... } ,但是我返回了一个对象数组subNodes: [... ] ,因为我在这里对普通的 object 没有任何真正的意义。

Also, this will yield an empty subNodes array if an input node has no children.此外,如果输入节点没有子节点,这将产生一个空的subNodes数组。 If you would rather not have the subNodes property, you could replace如果您不想拥有subNodes属性,则可以替换

    subNode: children

with something like有类似的东西

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

Obviously, you don't need the named helpers and could call mapTree with anonymous functions like this:显然,您不需要命名助手,并且可以使用如下匿名函数调用mapTree

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

This mapTree function was very easy to write, as I didn't have to think about any details of the output or input formats as I wrote it.这个mapTree function 非常容易编写,因为我不必考虑 output 的任何细节或我编写它的输入格式。 But perhaps that abstraction is not helpful to me, and I'm never going to use it except here.但也许这种抽象对我没有帮助,除了这里我永远不会使用它。 If so, I can simply rework the abstract version by plugging the hard-coded callbacks directly.如果是这样,我可以通过直接插入硬编码的回调来简单地修改抽象版本。 With only a little manipulation, that will turn it into this version:只需一点点操作,它就会变成这个版本:

 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))


There's an important point here.这里有一个重要的点。 This generic function was much easier to write than if I'd tried to write something to convert your format directly.这个通用的 function 比我尝试写一些东西来直接转换你的格式要容易得多。 While there is a danger in too-early abstraction, it also can offer significant benefits.虽然过早抽象存在危险,但它也可以提供显着的好处。 I might well choose to keep only that last version, but the generic abstraction simplified the development of it.我可能会选择只保留最后一个版本,但通用抽象简化了它的开发。

It can be something like that, with using the json data model它可以是这样的,使用 json 数据 model

 <.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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM