Javascript 使用对象数组动态创建分组列表
我有一个嵌套的对象数组,如下所示:Javascript 使用对象数组动态创建分组列表,javascript,jquery,html,Javascript,Jquery,Html,我有一个嵌套的对象数组,如下所示: result = [ [{"country":"France","continent":"Europe","name":"street a"}], [{"country":"Brazil","continent":"South America", "name":"street b"},{"country":"Brazil","continent":"South America", "name":"street c"}
result = [
[{"country":"France","continent":"Europe","name":"street a"}],
[{"country":"Brazil","continent":"South America", "name":"street b"},{"country":"Brazil","continent":"South America", "name":"street c"}],
[{"country":"Germany","continent":"Europe","name":"street d"}]
]
请注意,这是从排序后的对象数组中生成的,先使用大陆键,然后使用国家/地区键
我想动态生成一个列表,如下所示(先是大陆,然后是国家),并将其添加到div
:
- 法国
- a街
- 德国
- d街
- 巴西
- b街
- c街
for(var i=0;i<result.length;i++){
if($('#continent-list li').filter(function(){
return $(this).text() == result[i][0].continent;
}).length == 0){
$('#continent-list').append('<li>'+result[i][0].continent+'<ul></ul></li>');
}
for(var i=0;i我认为一种方法是循环数组中的对象,为可用的大陆创建div,同时确保没有大陆被多次创建,然后仍然使用相同的循环,您可以使用
for(i=0;i<=results.length;i++){
if (result[i].continent == continent) //here talking about the present continent in the main loop{
//code to create new div for the current country....then same procedure for the street part....
}
}
for(i=0;ivar国家=[[{“国家”:“法国”、“大陆”:“欧洲”、“名称”:“街道a”}],{“国家”:“巴西”、“大陆”:“南美洲”、“名称”:“街道b”}{“国家”:“巴西”、“大陆”:“南美洲”、“名称”:“街道c”}],{“国家”:“德国”、“大陆”:“欧洲”、“名称”:“街道d”}];
var-modified={};
对于(var i=0;i我将让您处理重复项,但这将为您提供总体思路:
您可以展开数组,按属性大陆
、国家
和街道
排序,并在更改组时构建所有新列表
var result=[[{“国家”:“法国”、“大陆”:“欧洲”、“名称”:“街道a”}],{“国家”:“巴西”、“大陆”:“南美洲”、“名称”:“街道b”},{“国家”:“巴西”、“大陆”:“南美洲”、“名称”:“街道c”}],{“国家”:“德国”、“大陆”:“欧洲”、“名称”:“街道d”}],
平坦=结果。减少(函数(r,a){
返回r.concat(a);
}, []),
ol=document.createElement('ol'),
ul1,ul2;
平面排序(函数(a,b){
返回a.continent.localeCompare(b.continent)| | a.country.localeCompare(b.country)| | a.name.localeCompare(b.name);
});
flat.forEach(函数(a、i、aa){
李华;
如果(!i | | aa[i-1].大陆!==a.大陆){
li=document.createElement('li');
li.appendChild(document.createTextNode(a.contraction));
l.儿童(李);
ul1=document.createElement('ul');
其他儿童(ul1);
}
如果(!i | | aa[i-1].country!==a.country){
li=document.createElement('li');
li.appendChild(document.createTextNode(a.country));
ul1.儿童(li);
ul2=document.createElement('ul');
ul1.附肢儿童(ul2);
}
li=document.createElement('li');
li.appendChild(document.createTextNode(a.name));
ul2.儿童(li);
});
document.getElementById('out').appendChild(ol);
我认为大部分工作都可以使用array reduce函数完成;)
步骤1:我们将把您的阵列转换为您需要的结构:
var result = [
[{"country": "France", "continent": "Europe", "name": "street a"}],
[{"country": "Brazil", "continent": "South America", "name": "street b"}, {
"country": "Brazil",
"continent": "South America",
"name": "street c"
}],
[{"country": "Germany", "continent": "Europe", "name": "street d"}]
];
// fatten the arrays into single array
var continents = result.reduce(function (a, b) {
return a.concat(b);
});
// group by continent
continents = continents.reduce(function (a, b) {
if (a[b.continent]) {
a[b.continent].push(b);
} else {
a[b.continent] = [b];
}
return a;
}, {});
// group by country
Object.keys(continents).forEach(function (continent) {
continents[continent] = continents[continent].reduce(function (a, b) {
if (a[b.country]) {
a[b.country].push(b);
} else {
a[b.country] = [b];
}
return a;
}, {});
});
现在,您的大陆
数据对象应该是这样的:
{
"Europe": {
"France": [
{
"country": "France",
"continent": "Europe",
"name": "street a"
}
],
"Germany": [
{
"country": "Germany",
"continent": "Europe",
"name": "street d"
}
]
},
"South America": {
"Brazil": [
{
"country": "Brazil",
"continent": "South America",
"name": "street b"
},
{
"country": "Brazil",
"continent": "South America",
"name": "street c"
}
]
}
}
<ol id="continent-list">
<li class="continent"><span>Europe</span>
<ul class="country-list">
<li><span>France</span>
<ul class="street-list">
<li>street a</li>
</ul>
</li>
<li><span>Germany</span>
<ul class="street-list">
<li>street d</li>
</ul>
</li>
</ul>
</li>
<li class="continent"><span>South America</span>
<ul class="country-list">
<li><span>Brazil</span>
<ul class="street-list">
<li>street b</li>
<li>street c</li>
</ul>
</li>
</ul>
</li>
</ol>
步骤2:我们将使用JQuery将此对象转换为html元素:
// create continents list
var $list = $('<ol id="continent-list"/>');
Object.keys(continents).forEach(function (continentName) {
// create continent
var $continent = $('<li class="continent"/>').append($("<span/>").text(continentName));
// add countries
var $countries = $('<ul class="country-list"/>');
var continent = continents[continentName];
Object.keys(continent).forEach(function (countryName) {
var $country = $('<li/>').append($("<span/>").text(countryName));
// add streets
var $streets = $('<ul class="street-list"/>');
var country = continent[countryName];
country.forEach(function (street) {
var $street = $('<li/>').text(street.name);
$streets.append($street);
});
$country.append($streets);
$countries.append($country);
});
$continent.append($countries);
// add continent to the list
$list.append($continent);
});
步骤3只需将其附加到文档中,例如:
$("body").append($list);
这不是世界上最简单的需求/请求,但也不是特别复杂。它需要太多的代码才能解决,这让我感到困扰。我知道没有任何库可以让这个问题变得微不足道,但有两个库非常方便:
- 及
首先,您的记录嵌套过多。为了便于渲染,应将其展平。下划线可以在一行中完成此操作:
var flat = _.flatten(result);
在普通JS中这并不难:
var flat = [];
result.forEach(sublist => {
sublist.forEach(item => flat.push(item));
});
但能够“一蹴而就”并继续前进是件好事
然后您需要几个层次的嵌套。下划线有一个很好的groupBy
功能,但它是单层次的。还有其他多层次的扩展,但这更麻烦。不过,D3非常容易管理嵌套:
var nested = d3.nest()
.key(d => d.continent)
.key(d => d.country)
.entries(flat);
然后需要将嵌套的数据结构呈现为HTML。您可以直接对HTML进行呈现,但这有点混乱。谢天谢地,浏览器有很好的工具来管理DOM,也就是它们对HTML的内部表示。D3非常擅长处理它
function nested2html(e, n, level) {
level = level || 0;
if (typeof e === 'string') e = d3.select(e);
var list = e.append(level ? 'ul' : 'ol')
.attr('class', 'level' + (level+1));
var leafNode = !n[0].key;
n.forEach(nitem => {
if (leafNode) {
list.append('li').text(nitem.name);
} else {
var li = list.append('li');
li.append('span').text(nitem.key);
nested2html(li, nitem.values, level + 1);
}
});
}
// now add it to the document
nested2html('body', nested);
这并不像递归例程那样复杂,它呈现为结构良好、样式非常简单的HTML:
<ol class="level1">
<li>
<span>Europe</span>
<ul class="level2">
<li>
<span>France</span>
<ul class="level3">
<li>street a</li>
</ul>
</li>
<li>
<span>Germany</span>
<ul class="level3">
<li>street d</li>
</ul>
</li>
</ul>
</li>
<li>
<span>South America</span>
<ul class="level2">
<li>
<span>Brazil</span>
<ul class="level3">
<li>street b</li>
<li>street c</li>
</ul>
</li>
</ul>
</li>
</ol>
欧洲
-
法国
- a街
-
德国
- d街
南美洲
-
巴西
- b街
- c街
一个包含运行的代码的示例,以及一些显示如何设置结果样式的可选CSS
我只希望有一种方法可以更简洁地做到这一点。您的json中有一些语法错误。这些是真的还是问题中的输入错误?您能修复吗?这里没有json。请阅读json
标记的用法说明。
function nested2html(e, n, level) {
level = level || 0;
if (typeof e === 'string') e = d3.select(e);
var list = e.append(level ? 'ul' : 'ol')
.attr('class', 'level' + (level+1));
var leafNode = !n[0].key;
n.forEach(nitem => {
if (leafNode) {
list.append('li').text(nitem.name);
} else {
var li = list.append('li');
li.append('span').text(nitem.key);
nested2html(li, nitem.values, level + 1);
}
});
}
// now add it to the document
nested2html('body', nested);
<ol class="level1">
<li>
<span>Europe</span>
<ul class="level2">
<li>
<span>France</span>
<ul class="level3">
<li>street a</li>
</ul>
</li>
<li>
<span>Germany</span>
<ul class="level3">
<li>street d</li>
</ul>
</li>
</ul>
</li>
<li>
<span>South America</span>
<ul class="level2">
<li>
<span>Brazil</span>
<ul class="level3">
<li>street b</li>
<li>street c</li>
</ul>
</li>
</ul>
</li>
</ol>