【问题标题】:svelte:component with DOM elementssvelte:带有 DOM 元素的组件
【发布时间】:2021-07-20 04:05:54
【问题描述】:

目标

我正在 Svelte 中创建一个按钮组件,该组件将呈现为 <button><a> 元素,具体取决于它是否为链接。可以使用svelte:component吗?

这样的……

<script lang='ts'>
  export let href: string = ''

  $: component = href ? a : button // where "a" and "button" are the HTML DOM elements
</script>

<svelte:component this={component}>
 <slot></slot>
</svelte:component>

到目前为止,我只看到了 svelte:component 渲染自定义 Svelte 组件的示例,而不是 DOM 元素

https://svelte.dev/tutorial/svelte-component

How to dynamically render components in Svelte?

动机

可以使用 if/else 来获得想要的结果……

<script lang='ts'>
  export let href: string = ''
</script>

{# if href}
  <a {href}>
    <slot></slot>
  </a>
{:else}
  <button>
    <slot></slot>
  </button>
{/if}

...但是这是不可维护的。

  • 整个内容被复制。在上面的简单示例中,内容只是子项。实际上,有多个插槽(例如前缀/后缀),导致大量重复逻辑。
  • 我可以在许多其他具有 2 个以上变体的组件中看到这种设计模式的用途(例如,Container 组件可以是 divsectionarticleaside 等。 )。变体越多,代码结构就越混乱。

反应等效

这是一个具有所需功能的示例 React 组件。

const Button = (props) => {
  const Tag = props.href ? 'a' : 'button'

  return <Tag href={props.href}>{contents}</Tag>
}

我希望避免的解决方案

1。 if/else 模式

与上述相同的模式。

2。创建一个“子”组件

您可以将其移动到自己的组件中,然后将子项导入到 if/else 链中,而不是多次复制子项。至少那样不会有重复的逻辑,但道具/插槽将需要重复。

<script lang='ts'>
  import Children from './children.svelte'

  export let href: string = ''
</script>

{# if href}
  <a {href}>
    <Children><slot></slot></Children>
  </a>
{:else}
  <button>
    <Children><slot></slot></Children>
  </button>
{/if}

3。创建包装器组件

对于每个包装 DOM 元素,只需创建一个新的 Svelte 组件。然后,将它们作为实际的 Svelte 组件导入并使用 svelte:component

<!-- dom-a.svelte -->

<a {...$$props}><slot></slot></a>
<!-- dom-button.svelte -->

<button {...$$props}><slot></slot></button>
<!-- button.svelte -->
<script lang='ts'>
  import A from './dom-a.svelte'
  import Button from './dom-button.svelte'

  export let href: string = ''

  $: component = href ? A : Button
</script>

<svelte:component this={component}>
 <slot></slot>
</svelte:component>

虽然这是最适合作为开发人员使用的工具,但有一个 performance penalty 用于拥有未知道具。因此,这不是想法。

我想你可以在 dom-button.sveltedom-a.svelte 组件中指定每一个可能的道具,但这似乎有点矫枉过正。

【问题讨论】:

    标签: svelte svelte-3 svelte-component


    【解决方案1】:

    不能为此使用&lt;svelte:component&gt;。有一个proposal 可以为此功能添加一个新的&lt;svelte:element&gt; 标签,但它尚未实现。有一个open PR 可以将此标签添加到 Svelte。

    实施后,您将能够执行以下操作:

    <script lang='ts'>
      export let href: string = ''
    
      $: tagName = href ? 'a' : 'button';
    </script>
    
    <svelte:element tag={tagName}>
      <slot></slot>
    </svelte:element>
    

    在此之前,解决方法如您在问题中所述。

    【讨论】:

      猜你喜欢
      • 2020-02-10
      • 1970-01-01
      • 2021-10-16
      • 2020-12-05
      • 1970-01-01
      • 2019-05-29
      • 2016-06-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多