Svelte如何实现全局/Super Slots?多页面内容聚合到命名插槽
实现方法:通过上下文API收集嵌套路由的插槽内容
Svelte默认的命名插槽在路由嵌套时,子路由的同名插槽会覆盖父级内容,没法直接实现多路由插槽内容累加。要达到需求,需要借助Svelte上下文API来收集所有嵌套路由的safely插槽内容,再在根布局统一渲染。
步骤1:创建插槽内容收集的上下文模块
新建src/lib/safeSlot.js,用来管理插槽内容的存储和操作:
import { writable } from 'svelte/store'; import { setContext, getContext } from 'svelte'; // 用Symbol作为上下文唯一标识,避免冲突 const SAFE_SLOT_KEY = Symbol('safe-slot'); // 在根布局初始化上下文 export function createSafeSlotContext() { const { subscribe, update } = writable([]); // 添加插槽内容的方法 const addSlot = (content) => { update(items => [...items, content]); // 返回移除当前内容的函数,用于组件销毁时清理 return () => update(items => items.filter(item => item !== content)); }; setContext(SAFE_SLOT_KEY, { addSlot, subscribe }); } // 获取上下文的方法 export function getSafeSlotContext() { return getContext(SAFE_SLOT_KEY); }
步骤2:修改根布局__layout.svelte
在根布局中初始化上下文,并订阅收集到的插槽内容,统一渲染:
<script> import { createSafeSlotContext, getSafeSlotContext } from '$lib/safeSlot'; const hi = "hi"; // 初始化上下文 createSafeSlotContext(); let safeContents = []; // 订阅插槽内容的变化 const { subscribe } = getSafeSlotContext(); subscribe(items => { safeContents = items; }); </script> <h1>{hi}</h1> <slot /> <!-- 渲染所有收集到的safely插槽内容 --> {#each safeContents as content} {content} {/each}
步骤3:在子路由中收集插槽内容
以./route/to/something/index.svelte为例,修改组件,将safely插槽的内容添加到上下文:
<script> import { getSafeSlotContext } from '$lib/safeSlot'; import { onMount, onDestroy } from 'svelte'; import CustomComponent from '$lib/CustomComponent.svelte'; const { addSlot } = getSafeSlotContext(); // 定义当前插槽的内容 const slotContent = <CustomComponent>first</CustomComponent>; let removeSlot; onMount(() => { // 挂载时添加插槽内容到上下文,拿到移除函数 removeSlot = addSlot(slotContent); }); onDestroy(() => { // 组件销毁时移除当前插槽内容,避免路由切换后残留 removeSlot(); }); </script> <p> in this page we have safely components </p>
同样修改./in/another/nested/component/index.svelte:
<script> import { getSafeSlotContext } from '$lib/safeSlot'; import { onMount, onDestroy } from 'svelte'; import CustomComponent from '$lib/CustomComponent.svelte'; const { addSlot } = getSafeSlotContext(); const slotContent = <CustomComponent>second</CustomComponent>; let removeSlot; onMount(() => { removeSlot = addSlot(slotContent); }); onDestroy(() => { removeSlot(); }); </script> <p> another safely component </p>
说明
这种方式完全基于Svelte原生API实现,不需要额外依赖。如果是多层嵌套路由,只要每个需要贡献safely内容的路由组件都按此方式处理,根布局就能自动收集并渲染所有内容,满足你想要的累加效果。
内容的提问来源于stack exchange,提问作者Angel Ponce
相关产品推荐
相关产品推荐

