You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 10:40:25