如何使用预定义属性值渲染带参数的Svelte代码片段?
问题:Svelte中动态渲染带参数的Snippet触发错误
在Svelte文件中存在两个代码片段:一个类型为Snippet<[]>的无参数Snippet,另一个为Snippet<[string]>的带参数Snippet。尝试通过状态变量动态渲染带参数的Snippet时触发错误,复现代码如下:
<script lang="ts"> let useNoParamSnippet: boolean = $state(true); let textToUseInStringParamSnippet: string = $state("Hello"); let snippetToRender = $derived( useNoParamSnippet ? noParamSnippet : () => stringParamSnippet(textToUseInStringParamSnippet) ); </script> {#snippet noParamSnippet()} <p>No parameter snippet.</p> {/snippet} {#snippet stringParamSnippet(text: string)} <p>Snippet with parameter: {text}</p> {/snippet} <button onclick={() => useNoParamSnippet = !useNoParamSnippet}> Use other snippet </button> {@render snippetToRender()} {@render stringParamSnippet("This is another, non-dynamic instance of that same snippet.")}
触发的错误信息:
Uncaught Svelte error: invalid_snippet_arguments.
A snippet function was passed invalid arguments. Snippets should only be instantiated via{@render ...}.
由于带参数的Snippet还需在模板其他位置直接使用,不想将其改为无参数片段,需要可行的实现方式。
解决方案
问题根源是Svelte的Snippet不能像普通函数那样直接调用,必须通过{@render}指令完成实例化。以下两种方法可解决问题,同时保留原Snippet的复用性:
方法一:模板内动态判断渲染
直接在{@render}位置根据状态变量分支渲染,逻辑直观且符合Svelte的模板语法规范:
<script lang="ts"> let useNoParamSnippet: boolean = $state(true); let textToUseInStringParamSnippet: string = $state("Hello"); </script> {#snippet noParamSnippet()} <p>No parameter snippet.</p> {/snippet} {#snippet stringParamSnippet(text: string)} <p>Snippet with parameter: {text}</p> {/snippet} <button onclick={() => useNoParamSnippet = !useNoParamSnippet}> Use other snippet </button> {#if useNoParamSnippet} {@render noParamSnippet()} {:else} {@render stringParamSnippet(textToUseInStringParamSnippet)} {/if} {@render stringParamSnippet("This is another, non-dynamic instance of that same snippet.")}
方法二:包装为兼容的无参数Snippet
如果需要通过$derived统一管理渲染逻辑,可以将带参数的Snippet包装成无参数类型,通过闭包捕获状态变量,同时内部用{@render}正确实例化:
<script lang="ts"> let useNoParamSnippet: boolean = $state(true); let textToUseInStringParamSnippet: string = $state("Hello"); let snippetToRender = $derived<Snippet<[]>>( useNoParamSnippet ? noParamSnippet : () => { return {@render stringParamSnippet(textToUseInStringParamSnippet)}; } ); </script> {#snippet noParamSnippet()} <p>No parameter snippet.</p> {/snippet} {#snippet stringParamSnippet(text: string)} <p>Snippet with parameter: {text}</p> {/snippet} <button onclick={() => useNoParamSnippet = !useNoParamSnippet}> Use other snippet </button> {@render snippetToRender()} {@render stringParamSnippet("This is another, non-dynamic instance of that same snippet.")}
这种方式让$derived返回的所有值都统一为Snippet<[]>类型,既满足动态切换需求,又不破坏原Snippet的直接调用能力。
内容的提问来源于stack exchange,提问作者goose_lake
相关产品推荐
相关产品推荐

