根据类别Id划分列表的Mustache模板



给出一些JSON数据作为项目数组:

[
{
"category": 1,
"product": "Sugar"
},
{
"category": 1,
"product": "Oil"
},
{
"category": 2,
"product": "Spice"
},
{
"category": 3,
"product": "Salt"
},
{
"category": 3,
"product": "Eggs"
},
{
"category": 5,
"product": "Bread"
},
{
"category": 5,
"product": "Butter"
},
{
"category": 7,
"product": "Milk"
}
]

我如何使用Mustache.js渲染它,使项目按类别Id分组到单独的列表中,还为缺失的Id添加一个空占位符(在本例中为4和6),如:

<ul id="category-1">
<li>Sugar</li>
<li>Oil</li>
</ul>
<ul id="category-2">
<li>Spice</li>
</ul>
<ul id="category-3">
<li>Salt</li>
<li>Eggs</li>
</ul>
<ul id="category-4">
</ul>
<ul id="category-5">
<li>Bread</li>
<li>Butter</li>
</ul>
<ul id="category-6">
</ul>
<ul id="category-7">
<li>Milk</li>
</ul>

首先需要将数据转换为可以轻松地使用Mustache进行映射的格式。一旦你完成了这些,模板就变得相当简单了。

下面是基本的方法:

  1. 找到数据中最大的类别号,并保存为largestCategoryNumber
  2. 创建一个长度为largestCategoryNumber的数组
  3. 用对象填充该数组,其中category的值是数组索引,product的值是原始数据中具有该类别编号
  4. 的产品
  5. 渲染模板

const data = [
{
"category": 1,
"product": "Sugar"
},
{
"category": 1,
"product": "Oil"
},
{
"category": 2,
"product": "Spice"
},
{
"category": 3,
"product": "Salt"
},
{
"category": 3,
"product": "Eggs"
},
{
"category": 5,
"product": "Bread"
},
{
"category": 5,
"product": "Butter"
},
{
"category": 7,
"product": "Milk"
}
];
const largestCategoryNumber = Math.max(
...data.map(({category}) => category)
);
const formattedData = [];
Array.from(Array(largestCategoryNumber)).forEach((_, index) => {
formattedData.push({
category: index,
products: data
.filter(obj => obj.category === index)
.map(({product}) => product)
});
});
const templateData = { data: formattedData };
window.onload = () => {
const template = document.getElementById('template').innerHTML;
const rendered = Mustache.render(template, templateData);
document.getElementById('target').innerHTML = rendered;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.7.2/mustache.min.js"></script>
<div id="target"></div>
<script id="template" type="x-tmpl-mustache">
{{#data}}
<ul class="category-{{category}}">
{{#products}}
<li>{{.}}</li>
{{/products}}
</ul>
{{/data}}
</script>

我认为我们需要根据我们的需要改变响应:

const data = response;
const dataMap = data.reduce((r,v) =>{
return{
...r,
[v.category]:[
...r?.[v.category]||[],
{product: v.product} 
]
};
},{});

在UI:result dataMap is

{
"1": [
{
"product": "Sugar"
},
{
"product": "Oil"
}
],
"2": [
{
"product": "Spice"
}
],
"3": [
{
"product": "Salt"
},
{
"product": "Eggs"
}
],
"5": [
{
"product": "Bread"
},
{
"product": "Butter"
}
],
"7": [
{
"product": "Milk"
}
]
}

我们可以在ui 中使用

for (i of Object.keys(dataMap)) {
// i for category 
// dataMap[i] for array product
}

希望能有所帮助。

找到了一个解决方案,它确实涉及到适合Mustache模板格式的数据转换,但执行的迭代次数比下面cjl750的答案要少(它为每个项目执行filtermap):

// fill data array with empty/no products for all categories (max 7 in this case)
for (let i = 1; i < 8; i++)
data.push({ category: i });
// group by categories and add products
const grouped = Object.values(data.reduce((r, i) => {
r[i.category] = r[i.category] || { category: i.category, products: [] };
if (i.product)
r[i.category].products.push({ product: i.product });
return r;
}, {}));

将数据数组转换为分组对象数组,如:

[
{
"category": 1,
"products": [
{ "product": "Sugar" },
{ "product": "Oil" }
]
},
:
:
]

现在模板可以简单地:

<template id="template">
{{#.}}
<ul class="category-{{category}}">
{{#products}}
<li>{{product}}</li>
{{/products}}
</ul>
{{/.}}
</template>

最新更新