SvelteKit递归组件中如何正确传递插槽内容?
解决SvelteKit递归组件插槽传递问题
要解决<svelte:self>递归调用时插槽无法正常传递的问题,核心是将父组件传入的插槽模板转发给递归子组件,并确保子组件的每个item能正确传入插槽。
问题原因
你之前尝试的写法错误地将当前父级循环的item传递给了子组件的插槽,导致所有子项重复渲染父级内容。正确的做法是让子组件使用自己循环的子级item来调用父组件的插槽模板。
修改后的NestedList.svelte代码
仅需修改递归调用<svelte:self>的部分:
// lib/components/NestedList.svelte <script lang="ts"> type T = $$Generic<{ id: number; children?: T[]; }>; export let items: T[]; export let level = 1; export let activeID: number; // 假设已实现expanded和toggle函数 let collapsedItems = new Set<number>(); const expanded = (item: T) => !collapsedItems.has(item.id) || item.id === activeID; const toggle = (item: T) => { collapsedItems.has(item.id) ? collapsedItems.delete(item.id) : collapsedItems.add(item.id); }; </script> <ul class="level-{level}"> {#each items as item (item.id)} <li> <div> <div class="toggler"> {#if item.children?.length} <button class="as-link" class:expanded={expanded(item)} type="button" on:click={() => toggle(item)} /> {/if} </div> <slot {item} /> </div> {#if item.children?.length && expanded(item)} <!-- 关键修改:转发父插槽并传入子组件的item --> <svelte:self items={item.children} level={level + 1} {activeID}> {@render $$slots.default({ item })} </svelte:self> {/if} </li> {/each} </ul>
原理说明
$$slots.default是父组件传入的默认插槽,本质是一个可接收参数的渲染函数。- 在递归调用
<svelte:self>时,通过{@render}调用该插槽函数,并传入子组件循环的item(此上下文的item为子级数据)。 - 所有递归层级的组件都会复用父组件传入的插槽模板,且正确绑定当前层级的item数据。
父页面调用方式保持不变
<div id="list"> <NestedList items={filteredLocations} activeID={+$page.params.locationId} let:item> <LocationRow location={item} /> </NestedList> </div>
修改后,所有递归层级的子项都会正确渲染对应的<LocationRow>组件,插槽内容可正常传递到深层级。
内容的提问来源于stack exchange,提问作者Kevin Renskers
相关产品推荐
相关产品推荐

