如何从JSON数据递归创建UL / LI - 多层深层

时间:2022-11-28 09:17:31

I am trying to use use the following JSON data to create the following similar structure in a recursive inner function with not much luck, really need some help and so if anyone can assist please do. Thank you in advance.

我试图使用以下JSON数据在递归内部函数中创建以下类似的结构,运气不大,真的需要一些帮助,所以如果有人可以协助请做。先谢谢你。

<ul>
    <li></li>
    <li>
        <a href=""></a>
        <div>
            <ul>
                <li>
                    <a href=""></a>
                    <div>
                         ....etc
                    </div>
                </li>
            </ul>
        </div>
    </li>
</ul>

the JSON data I am using is as follows:

我使用的JSON数据如下:

    var JSON = {
    menu: [
        {id: '0',sub: [
            {name: 'lorem ipsum 0-0',link: '0-0', sub: null},
            {name: 'lorem ipsum 0-1',link: '0-1', sub: null},
            {name: 'lorem ipsum 0-2',link: '0-2', sub: null}
            ]
        },
        {id: '1',sub: null},
        {id: '2',sub: [
            {name: 'lorem ipsum 2-0',link: '2-0', sub: null},
            {name: 'lorem ipsum 2-1',link: '2-1', sub: null},
            {name: 'lorem ipsum 2-2',link: '2-2', sub: [
                {name: 'lorem ipsum 2-2-0',link: '2-2-0', sub: null},
                {name: 'lorem ipsum 2-2-1',link: '2-2-1', sub: null},
                {name: 'lorem ipsum 2-2-2',link: '2-2-2', sub: null},
                {name: 'lorem ipsum 2-2-3',link: '2-2-3', sub: null},
                {name: 'lorem ipsum 2-2-4',link: '2-2-4', sub: null},
                {name: 'lorem ipsum 2-2-5',link: '2-2-5', sub: null},
                {name: 'lorem ipsum 2-2-6',link: '2-2-6', sub: null}
            ]},
            {name: 'lorem ipsum 2-3',link: '2-3', sub: null},
            {name: 'lorem ipsum 2-4',link: '2-4', sub: null},
            {name: 'lorem ipsum 2-5',link: '2-5', sub: null}
            ]
        },
        {id: '3',sub: null}
    ]
}

and the code I have created (incomplete, this is the brain teaser I need help on) is:

我创建的代码(不完整,这是我需要帮助的脑筋急转弯)是:

$(function(){

    $.fn.dropdown = function(settings){
        var that = this;
        var settings = $.extend({}, $.fn.dropdown.defaults, settings);
        var methods = {
            isArray: function(o){
                return Object.prototype.toString.call(o) === '[object Array]';
            },
            createDropdownCode: function(arr){
                var menu = arr.menu;
                var html = null;
                var menusort = function(menu){
                    html = that;

                    that.find("li").each(function(idx){

                        var menuList = menu[idx].sub;
                        var baseContainer = $(this);
                        var count = -1;

                        var subsort = (function(){

                            count += 1;

                            return function(submenu, pb){

                                var subblock;
                                subblock = $("<div />").append('<ul />');

                                if(methods.isArray(submenu)){

                                    for(var i=0;i<submenu.length;i++){

                                        var l = $("<li />").append("<a href='"+ submenu[i].link +"'>"+ submenu[i].name +"</a>");

                                        subblock.find('ul').append(l);

                                        if(pb !== undefined && i == submenu.length-1){
                                            pb.append(subblock)
                                        }

                                        if(methods.isArray(submenu[i].sub)){
                                            subsort(submenu[i].sub, subblock.find('ul li').eq(i));
                                        }

                                    }
                                }
                            }
                        })()
                        subsort(menuList)
                    })
                }
                menusort(menu);
                return null; //html !== null ? html.html() : null;
            },
            init: function(){

                // filter through json
                // create the div=>ul=>li
                if(settings.jsonData === undefined || settings.jsonData === null){
                    console.warn('No JSON Data passed')
                    return;
                }else{
                    if(!methods.isArray(settings.jsonData.menu)){
                        console.warn('No JSON Data passed')
                        return; // error, no data!
                    }
                }


                //var html = methods.createBlock(settings.jsonData.menu[0].sub);
                var html = methods.createDropdownCode(settings.jsonData);
                //console.log(html) 
            }
        }

        methods.init();

        return that;

    }

    $.fn.dropdown.defaults = {
        jsonData: null
    }

})

$('#menu').dropdown({
    jsonData: JSON
});

integrated code used, thanks to the individual that gave a close enough answer - Although will study the others.

使用综合代码,感谢个人提供足够接近的答案 - 虽然会研究其他人。

$.fn.dropdown = function(settings){

    var that = this;
    var settings = $.extend({}, $.fn.dropdown.defaults, settings);

    var methods = {
        createDropDownCode: function(arr){

            // loop through li's of primary menu
            that.find("li").each(function(idx){

                $(this).append( menusort(arr.menu[idx].sub) );

                function menusort(data){
                    if(data !== null)   
                        var html = "<div><ul>";

                    for(item in data){
                        html += "<li>";
                        if(typeof(data[item].sub) === 'object'){
                            html += "<a href='" + data[item].link + "'>" + data[item].name + "</a>";
                            if($.isArray(data[item].sub))
                                html += menusort(data[item].sub);
                        }
                        html += "</li>"
                    }
                    if(data !== null)
                        html += "</ul></div>";
                    return html;
                }
            })
        },
        init: function(){
            var html = methods.createDropDownCode(settings.jsonData);

        }
    }

    methods.init();

}

7 个解决方案

#1


13  

You can try this recursive function I've just coded:

您可以尝试我刚刚编写的这个递归函数:

function buildList(data, isSub){
    var html = (isSub)?'<div>':''; // Wrap with div if true
    html += '<ul>';
    for(item in data){
        html += '<li>';
        if(typeof(data[item].sub) === 'object'){ // An array will return 'object'
            if(isSub){
                html += '<a href="' + data[item].link + '">' + data[item].name + '</a>';
            } else {
                html += data[item].id; // Submenu found, but top level list item.
            }
            html += buildList(data[item].sub, true); // Submenu found. Calling recursively same method (and wrapping it in a div)
        } else {
            html += data[item].id // No submenu
        }
        html += '</li>';
    }
    html += '</ul>';
    html += (isSub)?'</div>':'';
    return html;
}

It returns the html for the menu, so use it like that: var html = buildList(JSON.menu, false);

它返回菜单的html,所以使用它:var html = buildList(JSON.menu,false);

I believe it is faster because it's in pure JavaScript, and it doesn't create text nodes or DOM elements for every iteration. Just call .innerHTML or $('...').html() at the end when you're done instead of adding HTML immediately for every menu.

我相信它更快,因为它是纯JavaScript,并且它不会为每次迭代创建文本节点或DOM元素。只需在完成后调用.innerHTML或$('...')。html(),而不是立即为每个菜单添加HTML。

JSFiddled: http://jsfiddle.net/remibreton/csQL8/

JSFiddled:http://jsfiddle.net/remibreton/csQL8/

#2


6  

Make two functions makeUL and makeLI. makeUL calls makeLI on each element, and makeLI calls makeUL if there's sub elements:

制作两个函数makeUL和makeLI。 makeUL在每个元素上调用makeLI,如果有子元素,makeLI调用makeUL:

function makeUL(lst) {
    ...
    $(lst).each(function() { html.push(makeLI(this)) });
    ...
    return html.join("\n");
}

function makeLI(elem) {
    ...
    if (elem.sub)
        html.push('<div>' + makeUL(elem.sub) + '</div>');
    ...
    return html.join("\n");
}

http://jsfiddle.net/BvDW3/

http://jsfiddle.net/BvDW3/

Needs to be adapted to your needs, but you got the idea.

需要适应您的需求,但您明白了。

#3


2  

This solution uses a single recursive function. I simplified logic by using Array's map() prototype function.

此解决方案使用单个递归函数。我通过使用Array的map()原型函数简化了逻辑。

$(function () {
    $("body").html(makeUnorderedList(getData().menu));
});

function makeUnorderedList(data, li) {
    return $('<ul>').append(data.map(function (el) {
        var li = li || $('<li>');
        if (el.id || el.link) li.append($('<a>', {
            text : el.id || el.link,
            href : '#' + (el.id || el.link),
            name : el.name
        }));
        if (el.sub) li.append(makeUnorderedList(el.sub, li));
        return li;
    }));
}

function getData() {
    return {
        menu: [{
            id: '0',
            sub: [{
                name: 'lorem ipsum 0-0',
                link: '0-0',
                sub: null
            }, {
                name: 'lorem ipsum 0-1',
                link: '0-1',
                sub: null
            }, {
                name: 'lorem ipsum 0-2',
                link: '0-2',
                sub: null
            }]
        }, {
            id: '1',
            sub: null
        }, {
            id: '2',
            sub: [{
                name: 'lorem ipsum 2-0',
                link: '2-0',
                sub: null
            }, {
                name: 'lorem ipsum 2-1',
                link: '2-1',
                sub: null
            }, {
                name: 'lorem ipsum 2-2',
                link: '2-2',
                sub: [{
                    name: 'lorem ipsum 2-2-0',
                    link: '2-2-0',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-1',
                    link: '2-2-1',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-2',
                    link: '2-2-2',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-3',
                    link: '2-2-3',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-4',
                    link: '2-2-4',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-5',
                    link: '2-2-5',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-6',
                    link: '2-2-6',
                    sub: null
                }]
            }, {
                name: 'lorem ipsum 2-3',
                link: '2-3',
                sub: null
            }, {
                name: 'lorem ipsum 2-4',
                link: '2-4',
                sub: null
            }, {
                name: 'lorem ipsum 2-5',
                link: '2-5',
                sub: null
            }]
        }, {
            id: '3',
            sub: null
        }]
    };
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


Extension

Here is a more dynamic approach. You get to choose how your list items are rendered and what the child property is. The mapFunc paramater is a callback that gives you access to the current child node and its parent.

这是一种更有活力的方法。您可以选择如何呈现列表项以及子属性是什么。 mapFunc参数是一个回调,使您可以访问当前子节点及其父节点。

The scope of the mapFunc is the item. So you could use item as well as this to refer to said item.

mapFunc的范围是项目。所以你可以使用item以及这个来引用所述项目。

$(function () {
    $("body").html(makeUnorderedList(getData().menu, function(item, index, parent) {
      // `item` and `this` are the same.
      return $('<a>', {
            text : (item.id || item.link),
            href : '#' + (item.id || item.link),
            name : item.name,
            'data-index' : index
        });
    }, 'sub'));
});

function makeUnorderedList(data, mapFunc, childProp, li, parent) {
    return $('<ul>').append(data.map(function (el, index) {
        var li = li || $('<li>');
        li.append(mapFunc.call(el, el, index, parent));
        if (el[childProp]) {
            li.append(makeUnorderedList(el[childProp], mapFunc, childProp, li, data));
        }
        return li;
    }));
}

#4


1  

Fiddle

小提琴

Code:

码:

JS

var jsonstring = [{
  "id": '1',
  "children": [{
    "id": '2'
  }, {
    "id": '3',
    "children": [{
      "id": '4'
    }]
  }]
}, {
  "id": '5'
}];

 var htmlStr= recurse( jsonstring );
$('#test').append(htmlStr);


function recurse( data ) {
  var htmlRetStr = "<ul>"; 
  for (var key in data) { 
        if (typeof(data[key])== 'object' && data[key] != null) {
        var x=key*1;        
        if(isNaN(x)){
            htmlRetStr += "<li>" + key + ":<ul>";
            }
            htmlRetStr += recurse( data[key] );
            htmlRetStr += '</ul></li>';
        } else {
            htmlRetStr += ("<li>" + key + ': &quot;' + data[key] + '&quot;</li  >' );
        }
  };
  htmlRetStr += '</ul >';    
  return( htmlRetStr );
}

HtML

<div id="test"></div>

CSS

li ul ul li {
    padding-left: 10px;
}

li ul ul ul {
    padding: 0px;
}

#5


1  

This is like a complete solution for generating UL/LI recursively from JSON config, which has customizable classes for each node and support of expand and collapse events for each node. This provides just a basic working model, from which you ll be able to expand and customize to your needs.

这就像是从JSON配置递归生成UL / LI的完整解决方案,JSON配置为每个节点提供可自定义的类,并支持每个节点的展开和折叠事件。这只提供了一个基本的工作模型,您可以从中扩展和定制您的需求。

I found this answer from https://techmeals.com/fe/questions/javascript/6/How-can-I-create-a-dynamic-tree-of-UL-and-LI-from-JSON-config

我从https://techmeals.com/fe/questions/javascript/6/How-can-I-create-a-dynamic-tree-of-UL-and-LI-from-JSON-config找到了这个答案

Example JSON config file:

示例JSON配置文件:

var config = {
    "Menu-1-Level-1": {
        "label": "Menu-1-Level-1",
        "type": "treeView",
        "class": "Menu-1-Level-1",
        "children": [
            {
                label: "Menu-1-Level-2",
                type: "treeView",
                "class": "Menu-1-Level-2",
                children: [
                    {
                        label: "Menu-1-Level-3",
                        class: "Menu-1-Level-3"
                    }
                ]
            },
            {
                label : "Menu-2-Level-2",
                class: "Menu-2-Level-2"
            }
        ]
    },
    "Menu-2-Level-1": {
        "label": "Menu-2-Level-1",
        "type": "treeView",
        "class": "Menu-2-Level-1",
        "children": [
            {
                label: "Menu-1-Level-2",
                class: "Menu-1-Level-2",
                type: "treeView",
                children: [
                    {
                        label: "Menu-1-Level-3",
                        class: "Menu-1-Level-3"
                    }
                ]
            },
            {
                label : "Menu-2-Level-2",
                class : "Menu-2-Level-2"
            }
        ]
    }
};

HTML Code:

HTML代码:

<!DOCTYPE html>
<html>

<head>
    <title>Tree Menu</title>
    <script src="http://code.jquery.com/jquery-1.11.2.min.js" type="text/javascript"></script>
    <script src="tree.js" type="text/javascript"></script>
    <link href="tree.css" rel="stylesheet">
</head>

<body>
    <div class="treeContainer">
        <div class="tree"></div>
    </div>
    <script src="testPage.js" type="text/javascript"></script>
</body>

</html>

Tree.js

Tree.js

var tree;

tree = function (treeNodeParent, dataObj) {
    this.dataObj = dataObj;
    this.treeNodeParent = treeNodeParent;
    this.treeNode = $(document.createElement("ul")).addClass("treeNode");
};

tree.prototype.expandCollapse = function (e) {
    var target = $(e.currentTarget), parentLabel = target.parent();

    if (parentLabel.hasClass("collapsed")) {
        parentLabel.removeClass("collapsed").addClass("expanded");
    } else {
        parentLabel.addClass("collapsed").removeClass("expanded");
    }
};

tree.prototype.attachEvents = function () {
    var me = this;
    me.treeNodeParent.delegate(".collapsed label, .expanded label", "click", me.expandCollapse);
};

tree.prototype.attachMarkUp = function () {
    var me = this;
    me.treeNodeParent.append(me.treeNode);
};

tree.prototype.getEachNodeMarkup = function (nodeObj, rootNode, selector) {
    var selectedNode, i, me = this;

    if (nodeObj.children) {

        if (!selector) {
            selectedNode = rootNode;
        } else {
            selectedNode = rootNode.find(selector);
        }

        nodeObj.class = nodeObj.class ? nodeObj.class : "";
        selectedNode.append($.parseHTML("<li name=" + nodeObj.label + " class='collapsed " + nodeObj.class + "'>" + "<label>" + nodeObj.label + "</label>" + "<ul></ul></li>"));
        selector = selector + " li[name=" + nodeObj.label + "] > ul";

        for (i = 0; i < nodeObj.children.length; i = i + 1) {
            me.getEachNodeMarkup(nodeObj.children[i], rootNode, selector);
        }

    } else {
        nodeObj.class = nodeObj.class ? nodeObj.class : "";
        rootNode.find(selector).append($.parseHTML("<li name=" + nodeObj.label + " class='" + nodeObj.class + "'>" + "<label>" + nodeObj.label + "</label>" + "</li>"));
    }
};

tree.prototype.getTree = function () {
    var component, me = this;

    for (component in me.dataObj) {
        if (me.dataObj.hasOwnProperty(component)) {
            me.getEachNodeMarkup(me.dataObj[component], me.treeNode, "");
        }
    }
    me.attachMarkUp();
    me.attachEvents();
    return me.treeNode;
};

Tree.css

Tree.css

.treeNode .collapsed > ul, .collapsed > li {
    display: none;
}

.treeNode .expanded > ul, .expanded > li {
    display: block;
}

testPage.js

testPage.js

// the variable "config" is nothing but the config JSON defined initially. 
treeNode = new tree($('.treeContainer .tree'), config); 
treeNodeObj = treeNode.getTree();

Look at the example provided at https://jsfiddle.net/3s3k3zLL/

查看https://jsfiddle.net/3s3k3zLL/上提供的示例

#6


1  

Pure ES6

纯ES6

var foo=(arg)=>
`<ul>
${arg.map(elem=>
    elem.sub?
        `<li>${foo(elem.sub)}</li>`
        :`<li>${elem.name}</li>`
    )}
</ul>`

JSON example

JSON示例

   var bar = [
  {
    name: 'Home'
  }, {
    name: 'About'
  }, {
    name: 'Portfolio'
  }, {
    name: 'Blog'
  }, {
    name: 'Contacts'
  }, {
    name: 'Features',
    sub: [
      {
        name: 'Multipage'
      }, {
        name: 'Options',
        sub: [
          {
            name: 'General'
          }, {
            name: 'Sidebars'
          }, {
            name: 'Fonts'
          }, {
            name: 'Socials'
          }
        ]
      }, {
        name: 'Page'
      }, {
        name: 'FAQ'
      }
    ]
  }
]
var result=foo(bar)

Your 'result' will be valid HTML

您的“结果”将是有效的HTML

#7


0  

I was searching for general parent child element function and I saw these answers, and I took some pieces of code from here and there and made this function. I decided to share my code as an answer, in case someone like me will find this post when he is searching for a general parent child html element draw function:

我正在寻找一般的父子元素功能,我看到了这些答案,我从这里和那里拿了一些代码并完成了这个功能。我决定分享我的代码作为答案,以防像我这样的人在搜索一般父子html元素绘制函数时会发现这篇文章:

function drawRecElements(arr, html, elements) {
    if (typeof (html) === 'undefined') {
        var html = '';
    }
    if (typeof (elements) === 'undefined') {
        var elements = {child: '<li>', childClose: '</li>', parent: '<ul>', parentClose: '</ul>'};
    }
    if (typeof (arr) === 'string') {
        return elements.child + arr + elements.childClose;
    } else if (typeof (arr) === 'object') {
        for (i in arr) {
            if (typeof (arr[i]) === 'string') {
                html += elements.parent + elements.child + i + elements.childClose + elements.child + arr[i] + elements.childClose + elements.parentClose;
            } else if(typeof (i) === 'string' && (isNaN(i))){
                html += elements.parent + elements.child + i + elements.childClose + elements.child + drawRecElements(arr[i],'',elements) + elements.childClose + elements.parentClose;
            } else if (typeof (arr[i]) === 'object') {
               html = drawRecElements(arr[i], html,elements);
            }
        }
    }
    return html;
}

https://jsfiddle.net/kxn442z5/1/

https://jsfiddle.net/kxn442z5/1/

#1


13  

You can try this recursive function I've just coded:

您可以尝试我刚刚编写的这个递归函数:

function buildList(data, isSub){
    var html = (isSub)?'<div>':''; // Wrap with div if true
    html += '<ul>';
    for(item in data){
        html += '<li>';
        if(typeof(data[item].sub) === 'object'){ // An array will return 'object'
            if(isSub){
                html += '<a href="' + data[item].link + '">' + data[item].name + '</a>';
            } else {
                html += data[item].id; // Submenu found, but top level list item.
            }
            html += buildList(data[item].sub, true); // Submenu found. Calling recursively same method (and wrapping it in a div)
        } else {
            html += data[item].id // No submenu
        }
        html += '</li>';
    }
    html += '</ul>';
    html += (isSub)?'</div>':'';
    return html;
}

It returns the html for the menu, so use it like that: var html = buildList(JSON.menu, false);

它返回菜单的html,所以使用它:var html = buildList(JSON.menu,false);

I believe it is faster because it's in pure JavaScript, and it doesn't create text nodes or DOM elements for every iteration. Just call .innerHTML or $('...').html() at the end when you're done instead of adding HTML immediately for every menu.

我相信它更快,因为它是纯JavaScript,并且它不会为每次迭代创建文本节点或DOM元素。只需在完成后调用.innerHTML或$('...')。html(),而不是立即为每个菜单添加HTML。

JSFiddled: http://jsfiddle.net/remibreton/csQL8/

JSFiddled:http://jsfiddle.net/remibreton/csQL8/

#2


6  

Make two functions makeUL and makeLI. makeUL calls makeLI on each element, and makeLI calls makeUL if there's sub elements:

制作两个函数makeUL和makeLI。 makeUL在每个元素上调用makeLI,如果有子元素,makeLI调用makeUL:

function makeUL(lst) {
    ...
    $(lst).each(function() { html.push(makeLI(this)) });
    ...
    return html.join("\n");
}

function makeLI(elem) {
    ...
    if (elem.sub)
        html.push('<div>' + makeUL(elem.sub) + '</div>');
    ...
    return html.join("\n");
}

http://jsfiddle.net/BvDW3/

http://jsfiddle.net/BvDW3/

Needs to be adapted to your needs, but you got the idea.

需要适应您的需求,但您明白了。

#3


2  

This solution uses a single recursive function. I simplified logic by using Array's map() prototype function.

此解决方案使用单个递归函数。我通过使用Array的map()原型函数简化了逻辑。

$(function () {
    $("body").html(makeUnorderedList(getData().menu));
});

function makeUnorderedList(data, li) {
    return $('<ul>').append(data.map(function (el) {
        var li = li || $('<li>');
        if (el.id || el.link) li.append($('<a>', {
            text : el.id || el.link,
            href : '#' + (el.id || el.link),
            name : el.name
        }));
        if (el.sub) li.append(makeUnorderedList(el.sub, li));
        return li;
    }));
}

function getData() {
    return {
        menu: [{
            id: '0',
            sub: [{
                name: 'lorem ipsum 0-0',
                link: '0-0',
                sub: null
            }, {
                name: 'lorem ipsum 0-1',
                link: '0-1',
                sub: null
            }, {
                name: 'lorem ipsum 0-2',
                link: '0-2',
                sub: null
            }]
        }, {
            id: '1',
            sub: null
        }, {
            id: '2',
            sub: [{
                name: 'lorem ipsum 2-0',
                link: '2-0',
                sub: null
            }, {
                name: 'lorem ipsum 2-1',
                link: '2-1',
                sub: null
            }, {
                name: 'lorem ipsum 2-2',
                link: '2-2',
                sub: [{
                    name: 'lorem ipsum 2-2-0',
                    link: '2-2-0',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-1',
                    link: '2-2-1',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-2',
                    link: '2-2-2',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-3',
                    link: '2-2-3',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-4',
                    link: '2-2-4',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-5',
                    link: '2-2-5',
                    sub: null
                }, {
                    name: 'lorem ipsum 2-2-6',
                    link: '2-2-6',
                    sub: null
                }]
            }, {
                name: 'lorem ipsum 2-3',
                link: '2-3',
                sub: null
            }, {
                name: 'lorem ipsum 2-4',
                link: '2-4',
                sub: null
            }, {
                name: 'lorem ipsum 2-5',
                link: '2-5',
                sub: null
            }]
        }, {
            id: '3',
            sub: null
        }]
    };
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


Extension

Here is a more dynamic approach. You get to choose how your list items are rendered and what the child property is. The mapFunc paramater is a callback that gives you access to the current child node and its parent.

这是一种更有活力的方法。您可以选择如何呈现列表项以及子属性是什么。 mapFunc参数是一个回调,使您可以访问当前子节点及其父节点。

The scope of the mapFunc is the item. So you could use item as well as this to refer to said item.

mapFunc的范围是项目。所以你可以使用item以及这个来引用所述项目。

$(function () {
    $("body").html(makeUnorderedList(getData().menu, function(item, index, parent) {
      // `item` and `this` are the same.
      return $('<a>', {
            text : (item.id || item.link),
            href : '#' + (item.id || item.link),
            name : item.name,
            'data-index' : index
        });
    }, 'sub'));
});

function makeUnorderedList(data, mapFunc, childProp, li, parent) {
    return $('<ul>').append(data.map(function (el, index) {
        var li = li || $('<li>');
        li.append(mapFunc.call(el, el, index, parent));
        if (el[childProp]) {
            li.append(makeUnorderedList(el[childProp], mapFunc, childProp, li, data));
        }
        return li;
    }));
}

#4


1  

Fiddle

小提琴

Code:

码:

JS

var jsonstring = [{
  "id": '1',
  "children": [{
    "id": '2'
  }, {
    "id": '3',
    "children": [{
      "id": '4'
    }]
  }]
}, {
  "id": '5'
}];

 var htmlStr= recurse( jsonstring );
$('#test').append(htmlStr);


function recurse( data ) {
  var htmlRetStr = "<ul>"; 
  for (var key in data) { 
        if (typeof(data[key])== 'object' && data[key] != null) {
        var x=key*1;        
        if(isNaN(x)){
            htmlRetStr += "<li>" + key + ":<ul>";
            }
            htmlRetStr += recurse( data[key] );
            htmlRetStr += '</ul></li>';
        } else {
            htmlRetStr += ("<li>" + key + ': &quot;' + data[key] + '&quot;</li  >' );
        }
  };
  htmlRetStr += '</ul >';    
  return( htmlRetStr );
}

HtML

<div id="test"></div>

CSS

li ul ul li {
    padding-left: 10px;
}

li ul ul ul {
    padding: 0px;
}

#5


1  

This is like a complete solution for generating UL/LI recursively from JSON config, which has customizable classes for each node and support of expand and collapse events for each node. This provides just a basic working model, from which you ll be able to expand and customize to your needs.

这就像是从JSON配置递归生成UL / LI的完整解决方案,JSON配置为每个节点提供可自定义的类,并支持每个节点的展开和折叠事件。这只提供了一个基本的工作模型,您可以从中扩展和定制您的需求。

I found this answer from https://techmeals.com/fe/questions/javascript/6/How-can-I-create-a-dynamic-tree-of-UL-and-LI-from-JSON-config

我从https://techmeals.com/fe/questions/javascript/6/How-can-I-create-a-dynamic-tree-of-UL-and-LI-from-JSON-config找到了这个答案

Example JSON config file:

示例JSON配置文件:

var config = {
    "Menu-1-Level-1": {
        "label": "Menu-1-Level-1",
        "type": "treeView",
        "class": "Menu-1-Level-1",
        "children": [
            {
                label: "Menu-1-Level-2",
                type: "treeView",
                "class": "Menu-1-Level-2",
                children: [
                    {
                        label: "Menu-1-Level-3",
                        class: "Menu-1-Level-3"
                    }
                ]
            },
            {
                label : "Menu-2-Level-2",
                class: "Menu-2-Level-2"
            }
        ]
    },
    "Menu-2-Level-1": {
        "label": "Menu-2-Level-1",
        "type": "treeView",
        "class": "Menu-2-Level-1",
        "children": [
            {
                label: "Menu-1-Level-2",
                class: "Menu-1-Level-2",
                type: "treeView",
                children: [
                    {
                        label: "Menu-1-Level-3",
                        class: "Menu-1-Level-3"
                    }
                ]
            },
            {
                label : "Menu-2-Level-2",
                class : "Menu-2-Level-2"
            }
        ]
    }
};

HTML Code:

HTML代码:

<!DOCTYPE html>
<html>

<head>
    <title>Tree Menu</title>
    <script src="http://code.jquery.com/jquery-1.11.2.min.js" type="text/javascript"></script>
    <script src="tree.js" type="text/javascript"></script>
    <link href="tree.css" rel="stylesheet">
</head>

<body>
    <div class="treeContainer">
        <div class="tree"></div>
    </div>
    <script src="testPage.js" type="text/javascript"></script>
</body>

</html>

Tree.js

Tree.js

var tree;

tree = function (treeNodeParent, dataObj) {
    this.dataObj = dataObj;
    this.treeNodeParent = treeNodeParent;
    this.treeNode = $(document.createElement("ul")).addClass("treeNode");
};

tree.prototype.expandCollapse = function (e) {
    var target = $(e.currentTarget), parentLabel = target.parent();

    if (parentLabel.hasClass("collapsed")) {
        parentLabel.removeClass("collapsed").addClass("expanded");
    } else {
        parentLabel.addClass("collapsed").removeClass("expanded");
    }
};

tree.prototype.attachEvents = function () {
    var me = this;
    me.treeNodeParent.delegate(".collapsed label, .expanded label", "click", me.expandCollapse);
};

tree.prototype.attachMarkUp = function () {
    var me = this;
    me.treeNodeParent.append(me.treeNode);
};

tree.prototype.getEachNodeMarkup = function (nodeObj, rootNode, selector) {
    var selectedNode, i, me = this;

    if (nodeObj.children) {

        if (!selector) {
            selectedNode = rootNode;
        } else {
            selectedNode = rootNode.find(selector);
        }

        nodeObj.class = nodeObj.class ? nodeObj.class : "";
        selectedNode.append($.parseHTML("<li name=" + nodeObj.label + " class='collapsed " + nodeObj.class + "'>" + "<label>" + nodeObj.label + "</label>" + "<ul></ul></li>"));
        selector = selector + " li[name=" + nodeObj.label + "] > ul";

        for (i = 0; i < nodeObj.children.length; i = i + 1) {
            me.getEachNodeMarkup(nodeObj.children[i], rootNode, selector);
        }

    } else {
        nodeObj.class = nodeObj.class ? nodeObj.class : "";
        rootNode.find(selector).append($.parseHTML("<li name=" + nodeObj.label + " class='" + nodeObj.class + "'>" + "<label>" + nodeObj.label + "</label>" + "</li>"));
    }
};

tree.prototype.getTree = function () {
    var component, me = this;

    for (component in me.dataObj) {
        if (me.dataObj.hasOwnProperty(component)) {
            me.getEachNodeMarkup(me.dataObj[component], me.treeNode, "");
        }
    }
    me.attachMarkUp();
    me.attachEvents();
    return me.treeNode;
};

Tree.css

Tree.css

.treeNode .collapsed > ul, .collapsed > li {
    display: none;
}

.treeNode .expanded > ul, .expanded > li {
    display: block;
}

testPage.js

testPage.js

// the variable "config" is nothing but the config JSON defined initially. 
treeNode = new tree($('.treeContainer .tree'), config); 
treeNodeObj = treeNode.getTree();

Look at the example provided at https://jsfiddle.net/3s3k3zLL/

查看https://jsfiddle.net/3s3k3zLL/上提供的示例

#6


1  

Pure ES6

纯ES6

var foo=(arg)=>
`<ul>
${arg.map(elem=>
    elem.sub?
        `<li>${foo(elem.sub)}</li>`
        :`<li>${elem.name}</li>`
    )}
</ul>`

JSON example

JSON示例

   var bar = [
  {
    name: 'Home'
  }, {
    name: 'About'
  }, {
    name: 'Portfolio'
  }, {
    name: 'Blog'
  }, {
    name: 'Contacts'
  }, {
    name: 'Features',
    sub: [
      {
        name: 'Multipage'
      }, {
        name: 'Options',
        sub: [
          {
            name: 'General'
          }, {
            name: 'Sidebars'
          }, {
            name: 'Fonts'
          }, {
            name: 'Socials'
          }
        ]
      }, {
        name: 'Page'
      }, {
        name: 'FAQ'
      }
    ]
  }
]
var result=foo(bar)

Your 'result' will be valid HTML

您的“结果”将是有效的HTML

#7


0  

I was searching for general parent child element function and I saw these answers, and I took some pieces of code from here and there and made this function. I decided to share my code as an answer, in case someone like me will find this post when he is searching for a general parent child html element draw function:

我正在寻找一般的父子元素功能,我看到了这些答案,我从这里和那里拿了一些代码并完成了这个功能。我决定分享我的代码作为答案,以防像我这样的人在搜索一般父子html元素绘制函数时会发现这篇文章:

function drawRecElements(arr, html, elements) {
    if (typeof (html) === 'undefined') {
        var html = '';
    }
    if (typeof (elements) === 'undefined') {
        var elements = {child: '<li>', childClose: '</li>', parent: '<ul>', parentClose: '</ul>'};
    }
    if (typeof (arr) === 'string') {
        return elements.child + arr + elements.childClose;
    } else if (typeof (arr) === 'object') {
        for (i in arr) {
            if (typeof (arr[i]) === 'string') {
                html += elements.parent + elements.child + i + elements.childClose + elements.child + arr[i] + elements.childClose + elements.parentClose;
            } else if(typeof (i) === 'string' && (isNaN(i))){
                html += elements.parent + elements.child + i + elements.childClose + elements.child + drawRecElements(arr[i],'',elements) + elements.childClose + elements.parentClose;
            } else if (typeof (arr[i]) === 'object') {
               html = drawRecElements(arr[i], html,elements);
            }
        }
    }
    return html;
}

https://jsfiddle.net/kxn442z5/1/

https://jsfiddle.net/kxn442z5/1/