在 Svelte 中对 {#each} 循环进行分组
Grouping over an {#each} loop in Svelte
我有一组非同类对象,每个对象都使用 <svelte:component this={type}>
组件在循环中呈现,我想将相同类型的相邻对象分组在 div.
例如,我有一些类似这样的代码:
<script>
let things = [
{type: A, content: "One"},
{type: B, content: "Two"},
{type: B, content: "Three"},
{type: A, content: "Four"}
];
</script>
{#each things as thing, i}
{()=>someMagicHere1(things, thing, i)}
<svelte:component this={thing.type}>
{()=>someMagicHere2(things, thing, i)}
{/each}
我希望输出像这样分组:
<div class="group type-A">
<div class="thing type-A">One</div>
</div>
<div class="group type-B">
<div class="thing type-B">Two</div>
<div class="thing type-B">Three</div>
</div>
<div class="group type-A">
<div class="thing type-A">Four</div>
</div>
在things
数组中,事物没有排序(实际上,它们是排序的,但按日期,与它们的类型无关),但想法是在视觉上将相同类型的事物组合在一起.理想情况下,我只能对某些类型进行分组(比如将所有类型 A 分组,但类型 B 将保持独立),但我觉得如果我可以分组,我将能够得出一个单独的解决方案。也有两种以上;这只是一个最小的示例。
在 Svelte 中,individual A 和 B 组件不能有像这样的部分 HTML 元素,因为 Svelte 不允许围绕未闭合元素的条件:
{#if groupStart}
<div class="group">
{/if}
在每个 someMagicHereX()
中,我可以用 {@html customTags}
输出一些 HTML 以获得我想要的 DOM 输出,但是我失去了样式封装和其他Svelte 组件的好处。
我真正想要的是更 "sveltian" 的解决方案。也许我需要用 use
创造一些新东西?大家有什么好主意吗?
更新: 我似乎遗漏的一个关键特性是任何控件最终都必须绑定到原始数据集。因此,即使数据以某种方式进行了转换,原始数据也必须在运行时更新,反之亦然。
不确定以下内容是否满足您的要求,因为我无法从您的问题中判断您是想保持值的顺序不变,还是想先按组重新排序。
我们的想法是重新排列您的数据,以便按照您想要的方式遍历它。为了适应布局而操纵数据总是比反过来更容易。
以下内容会将您的初始数组转换为具有以下结构的数组:
[
{
cssClass: 'type-A',
values: [ /* all objects of type 'A' */ ],
},
{
cssClass: 'type-B',
values: [ /* all objects of type 'B' */ ],
},
// etc.
]
数据转换非常简单:
let groups = things.reduce((curr, val) => {
let group = curr.find(g => g.cssClass === `type-${val.type}`)
if (group)
group.values.push(val)
} else {
curr.push({ cssClass: `type-${val.type}`, values: [ val ] })
}
return curr
}, [])
有了这个新的数据结构,很容易实现您想要的布局:
{#each groups as group}
<div class="group {group.cssClass}">
{#each group.values as value}
<div class="thing {group.cssClass}">
{value.content}
</div>
{/each}
</div>
{/each}
编辑:如果您优先考虑对象在初始数组中的顺序,则数据转换会略有不同。基本上,每次类型更改时,您都希望创建一个新的 'group'。
像下面这样的东西就可以了(请注意,苗条的 #each
结构将保持不变,只有数据转换发生变化):
let groups = things.reduce((curr, val) => {
let group = curr.length ? curr[curr.length - 1] : undefined
if (group && group.cssClass === `type-${val.type}`) {
group.values.push(val)
} else {
curr.push({ cssClass: `type-${val.type}`, values: [ val ] })
}
return curr
}, [])
我有一组非同类对象,每个对象都使用 <svelte:component this={type}>
组件在循环中呈现,我想将相同类型的相邻对象分组在 div.
例如,我有一些类似这样的代码:
<script>
let things = [
{type: A, content: "One"},
{type: B, content: "Two"},
{type: B, content: "Three"},
{type: A, content: "Four"}
];
</script>
{#each things as thing, i}
{()=>someMagicHere1(things, thing, i)}
<svelte:component this={thing.type}>
{()=>someMagicHere2(things, thing, i)}
{/each}
我希望输出像这样分组:
<div class="group type-A">
<div class="thing type-A">One</div>
</div>
<div class="group type-B">
<div class="thing type-B">Two</div>
<div class="thing type-B">Three</div>
</div>
<div class="group type-A">
<div class="thing type-A">Four</div>
</div>
在things
数组中,事物没有排序(实际上,它们是排序的,但按日期,与它们的类型无关),但想法是在视觉上将相同类型的事物组合在一起.理想情况下,我只能对某些类型进行分组(比如将所有类型 A 分组,但类型 B 将保持独立),但我觉得如果我可以分组,我将能够得出一个单独的解决方案。也有两种以上;这只是一个最小的示例。
在 Svelte 中,individual A 和 B 组件不能有像这样的部分 HTML 元素,因为 Svelte 不允许围绕未闭合元素的条件:
{#if groupStart}
<div class="group">
{/if}
在每个 someMagicHereX()
中,我可以用 {@html customTags}
输出一些 HTML 以获得我想要的 DOM 输出,但是我失去了样式封装和其他Svelte 组件的好处。
我真正想要的是更 "sveltian" 的解决方案。也许我需要用 use
创造一些新东西?大家有什么好主意吗?
更新: 我似乎遗漏的一个关键特性是任何控件最终都必须绑定到原始数据集。因此,即使数据以某种方式进行了转换,原始数据也必须在运行时更新,反之亦然。
不确定以下内容是否满足您的要求,因为我无法从您的问题中判断您是想保持值的顺序不变,还是想先按组重新排序。
我们的想法是重新排列您的数据,以便按照您想要的方式遍历它。为了适应布局而操纵数据总是比反过来更容易。
以下内容会将您的初始数组转换为具有以下结构的数组:
[
{
cssClass: 'type-A',
values: [ /* all objects of type 'A' */ ],
},
{
cssClass: 'type-B',
values: [ /* all objects of type 'B' */ ],
},
// etc.
]
数据转换非常简单:
let groups = things.reduce((curr, val) => {
let group = curr.find(g => g.cssClass === `type-${val.type}`)
if (group)
group.values.push(val)
} else {
curr.push({ cssClass: `type-${val.type}`, values: [ val ] })
}
return curr
}, [])
有了这个新的数据结构,很容易实现您想要的布局:
{#each groups as group}
<div class="group {group.cssClass}">
{#each group.values as value}
<div class="thing {group.cssClass}">
{value.content}
</div>
{/each}
</div>
{/each}
编辑:如果您优先考虑对象在初始数组中的顺序,则数据转换会略有不同。基本上,每次类型更改时,您都希望创建一个新的 'group'。
像下面这样的东西就可以了(请注意,苗条的 #each
结构将保持不变,只有数据转换发生变化):
let groups = things.reduce((curr, val) => {
let group = curr.length ? curr[curr.length - 1] : undefined
if (group && group.cssClass === `type-${val.type}`) {
group.values.push(val)
} else {
curr.push({ cssClass: `type-${val.type}`, values: [ val ] })
}
return curr
}, [])