javascript 我如何从 JSON 数据递归创建 UL/LI 的 - 多层深度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9362446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I recursively create a UL/LI's from JSON data - multiple layers deep
提问by quinton
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();
}
回答by Rémi Breton
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/
回答by georg
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
sub
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");
}
Needs to be adapted to your needs, but you got the idea.
需要根据您的需求进行调整,但您明白了。
回答by Serhii Bilyk
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
回答by Mr. Polywhirl
This solution uses a single recursive function. I simplified logic by using Array
's map()
prototype
function.
此解决方案使用单个递归函数。我通过使用Array
的map()
prototype
功能简化了逻辑。
$(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
paramater是一个回调,让你访问当前子节点和其父。
The scope of the mapFunc
is the item. So you could use item
as well as this
to refer to said item
.
的范围mapFunc
是项目。所以你可以使用item
asthis
来指代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;
}));
}
回答by Nadeemmnn Mohd
Code:
代码:
JS
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 + ': "' + data[key] + '"</li >' );
}
};
htmlRetStr += '</ul >';
return( htmlRetStr );
}
HtML
网页语言
<div id="test"></div>
CSS
CSS
li ul ul li {
padding-left: 10px;
}
li ul ul ul {
padding: 0px;
}
回答by HumbleGeek
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 的完整解决方案,它为每个节点提供可自定义的类,并支持每个节点的展开和折叠事件。这仅提供了一个基本的工作模型,您可以从中扩展和定制您的需求。
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
树.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
树.css
.treeNode .collapsed > ul, .collapsed > li {
display: none;
}
.treeNode .expanded > ul, .expanded > li {
display: block;
}
testPage.js
测试页面.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/
回答by talsibony
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;
}