Svelte带fallback的slot如何判断是否被父组件显式传入空内容
Svelte 具名slot空内容判断解决方案
问题根因
你当前使用$$slots.foo做判断的逻辑存在局限:该属性仅标记父组件是否显式声明了对应名称的slot,和slot传入的内容是否为空无关。只要父组件写了对应slot属性,不管内容是否为空,$$slots都会包含对应slot的key,所以会出现你遇到的传空slot仍渲染额外内容的问题。
通用解决方案
通过包裹slot的DOM节点判断实际渲染内容是否为空,兼容性最好,适用于所有Svelte 3/4版本:
<script> import { onMount } from 'svelte'; // 绑定slot的包裹节点 let fooSlotWrapper; // 标记slot是否有有效非空内容 let hasValidFooContent = false; onMount(() => { // 排除空文本节点、无实际子元素的情况 hasValidFooContent = Array.from(fooSlotWrapper.childNodes).some(node => { // 文本节点需要非空 if (node.nodeType === Node.TEXT_NODE) { return node.textContent.trim() !== ''; } // 元素节点、注释节点等默认视为有内容,可根据业务需求调整规则 return true; }); }); </script> <div class="component"> <!-- display: contents 避免额外节点破坏原有布局 --> <div bind:this={fooSlotWrapper} style="display: contents;"> <slot name="foo"> <div class="fallback-content"/> </slot> </div> <!-- 仅slot有非空内容时渲染额外元素 --> {#if hasValidFooContent} <div class="other-content">Bar</div> {/if} </div>
这个方案同时兼容三种场景:
- 父组件未传slot:渲染fallback内容,同时
hasValidFooContent为true,展示额外内容 - 父组件传非空slot:渲染传入内容,展示额外内容
- 父组件传空slot:无slot内容渲染,
hasValidFooContent为false,不展示额外内容
轻量替代方案(适用于可控业务场景)
如果你的业务中父组件传空slot的场景固定,也可以通过slot prop主动标记是否需要展示额外内容,无需操作DOM:
<!-- MyComp.svelte --> <script> let showOtherContent = true; const setShowOtherContent = (val) => { showOtherContent = val; } </script> <div class="component"> <slot name="foo" setShowOtherContent={setShowOtherContent}> <div class="fallback-content"/> </slot> {#if showOtherContent} <div class="other-content">Bar</div> {/if} </div>
父组件传空slot时主动关闭标记即可:
<MyComp> <div slot="foo" let:setShowOtherContent> {setShowOtherContent(false)} </div> </MyComp>
该方案适合内部组件库的可控场景,不需要额外DOM操作,但需要父组件配合传值。
内容的提问来源于stack exchange,提问作者untemps
相关产品推荐
相关产品推荐

