如何根据Svelte中的道具设置动态html标签

slu*_*ist 6 javascript svelte svelte-3

我正在创建一个Heading组件,svelte作为学习该框架基础知识的一部分。组件行为非常简单。

该组件将有一个名为 的道具level,它将相应地呈现适当的<h>标签。

例如。

<Heading level={3}> would render <h3>content</h3> 
<Heading level={1}> would render <h1>content</h1>
Run Code Online (Sandbox Code Playgroud)

我目前可以做到这一点,

<script>
  export let level = 3;
</script>

{#if level === 1}
  <h1>
   <slot></slot>
  </h1>
{:else if level === 2}
  <h2>
   <slot></slot>
  </h2>
{:else if level === 3}
  <h3>
   <slot></slot>
  </h3>
{:else if level === 4}
  <h4>
   <slot></slot>
  </h4>
{:else if level === 5}
  <h5>
   <slot></slot>
  </h5>
{/if}
Run Code Online (Sandbox Code Playgroud)

但这种感觉就像是一种非常幼稚的方法。有没有更好的方法来实现这种行为svelte ?

Aba*_*ver 27

Svelte 从 3.47.0 开始使用 标签对此提供本机支持svelte:element。例子:

<svelte:element this="h1">this will be rendered as a top-level heading</svelte:element>

<svelte:element this={tag}>will render the element named in 'tag'</svelte:element>

<svelte:element this={null}>will not render for falsey values</svelte:element>
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅文档教程。


Mik*_*amb 6

我知道你的问题是为了向组件提供一个数字道具来设置标题级别,但既然你以这个问题结束了你的OP:

但这种做法感觉非常幼稚。有没有更好的方法来实现这种行为 svelte ?

...为了使未来的读者受益,这里有一个更强大的解决方案来解决需要一个组件来生成标题标签的核心问题。

如果您不介意为页面上的每个内容部分使用包装器组件,则可以使用 Context API 生成完全上下文感知的标题标签并完全自动化。你需要:

  • 用于设置上下文的包装组件
  • 生成标题标签的组件
    • 标题标签组件接受一个 prop,这样你就可以向它提供你想要的内容

这是一个例子:

Section.svelte

<script>
  import { setContext, getContext } from 'svelte'

  let level

  // if we find a context has already been set in this component tree, 
  // it came from a parent/ancestor instance of Section.svelte

  if (getContext('headingLevel')) {
    // Increment the context because this is the next nesting level
    level = getContext('headingLevel') + 1
    setContext('headingLevel', level)
  } else {
    // otherwise this instance is the first of its kind in the hierarchy
    level = 2
    setContext('headingLevel', level)
  }
</script>

<section>
  <slot />
</section>
Run Code Online (Sandbox Code Playgroud)

HeadingTag.svelte

<script>
  import { getContext } from 'svelte'

  // prop to insert your desired contents into the heading tag
  export let message

  // get the context, but make sure we can't go higher than <h6>
  let level = Math.min(getContext('headingLevel'), 6)

  const render = () => `
    <h${level}>
      ${message}
    </h${level}>
  `

</script>

{@html render()}
Run Code Online (Sandbox Code Playgroud)

然后,在您的其他组件或页面中,像这样使用它

MyPage.svelte

<Section>
  <HeadingTag message={"hello"} />
  <!-- renders <h2>hello</h2> -->
  <Section>
    <HeadingTag message={"hello"} />
    <!-- renders <h3>hello</h3> -->
    <Section>
      <HeadingTag message={"hello"} />
      <!-- renders <h4>hello</h4> -->
    </Section>
  </Section>
</Section>

<Section>
  <HeadingTag message={"hello"} />
  <!-- renders <h2>hello</h2> -->
</Section>
Run Code Online (Sandbox Code Playgroud)

这也将与您的组件的嵌套方式无缝配合。

请注意,我的示例将其设置为首先假设每个页面在其内<h2>只有一个,并且不需要这种自动化。但是您可以根据需要调整它以适应您的用例,例如,如果您希望它从顶层开始......<h1><main><h1>

Section.svelte

<script>
  import { setContext, getContext } from 'svelte'

  let level

  if (getContext('headingLevel')) {
    level = getContext('headingLevel') + 1
    setContext('headingLevel', level)
  } else {
    // this and the HTML below are the only things that changed
    level = 1
    setContext('headingLevel', level)
  }
</script>

{#if level === 1}
  <main>
    <slot />
  </main>
{:else}
  <section>
    <slot />
  <section>
{/if}
Run Code Online (Sandbox Code Playgroud)

感谢有兴趣的人进一步阅读:我在 Heydon Pickering 的这篇文章中基于 React 的示例中在 Svelte 中采用了这个解决方案:

https://medium.com/@Heydon/managing-heading-levels-in-design-systems-18be9a746fa3


小智 5

尝试这个:

<script>
export let level = 3;
let displayText = "<h" + level + ">" +
                    "Sample header text" +
                  "</h" + level + ">";
</script>

<main>
    <div>
        {@html displayText}
    </div>
</main>
Run Code Online (Sandbox Code Playgroud)

您可以通过将 level 的值连接到标记中来将 html 构建为字符串,然后使用“@html”变量注释显示它,该注释将您的字符串解释为 html,而不是纯文本。