Svelte 一些特殊的 elements

tags: Svelte
category: Front-End
description: Svelte 一些特殊的 elements
created_at: 2023/04/18 22:00:00

cover image


回到 手把手開始寫 Svelte


前言

雖然上一篇在 Context 不小心偷偷帶到了其中一個特殊的元素(svelte:self),不過沒關係,這邊一次把他補齊。

有以下的特殊元素:

  • <svelte:self>
  • <svelte:component>
  • <svelte:element>
  • <svelte:window>
  • <svelte:document>
  • <svelte:body>
  • <svelte:head>
  • <svelte:options>
  • <svelte:fragment>

<svelte:self>

上一篇有提到,這就是可以遞迴(recursive)自己組件的元素。

這個組件因為是遞迴自己本身,所以不能放在頂層(這樣就沒有結束條件了)。

貼個官方範例:

<script>
    export let count;
</script>

{#if count > 0}
    <p>counting down... {count}</p>
    <svelte:self count="{count - 1}"/>
{:else}
    <p>lift-off!</p>
{/if}

<svelte:component>

這個類似於 Vue 當中的 <component :is="" />是個方便偷懶的東西

總之就是可以動態的去呈現組件,像是下面這樣:

<script lang="ts">
    import A from '../components/A.svelte';
    import B from '../components/B.svelte';
    import C from '../components/C.svelte';

    const components = [A, B, C];

    let selectedComponent = components[0];
</script>

<h1>App</h1>

<select bind:value={selectedComponent}>
    {#if selectedComponent.name === undefined}
        <option disabled selected value="">Please select item</option>
    {:else}
        {#each components as component (component.name)}
            <option value={component}>{component.name?.match(/Proxy<(.*)>/)?.[1]}</option>
        {/each}
    {/if}
</select>

<hr />

<svelte:component this={selectedComponent} />

那個 {component.name?.match(/Proxy<(.*)>/)?.[1]} 不是很重要,我只是為了讓他呈現出來的文字好看一些而已。

另外他也可以傳遞 props 下去,可以自己嘗試。


<svelte:element>

這個和前一個 <svelte:component> 很像,只是 component 是針對自訂的組件(也就是大小開頭的元素),而 element 只針對內建的元素。

<script lang="ts">
    const elements = ['h1', 'h2', 'h3'];

    let selectedElement = elements[0];
</script>

<h1>App</h1>

<select bind:value={selectedElement}>
    {#each elements as element (element)}
        <option value={element}>{element}</option>
    {/each}
</select>

<hr />

<svelte:element this={selectedElement}>{selectedElement}</svelte:element>

另外要注意的是,如果你動態指定元素的時候不能夠 bind:value,也就是下面這樣是不行的:

<script>
    let text = '';
</script>

<svelte:element this={'input'} bind:value={text} />

{text}

但是下面這樣可以,因為他不是動態指定:

<svelte:element this="input" bind:value={text} />

啊可是你這樣不如:

<input type="text" bind:value={text} />

然後也不能在動態帶入 void 元素的時候有內容。

如果你帶入 void 元素且有子元素,且

  • 靜態帶入: 會把子元素呈現在兄弟節點(sibling node)上,也就是呈現在之後。
  • 動態帶入: 會把子元素包進去但顯示不出來,且會出現一段提示訊息,例如: <svelte:element this="hr"> is self-closing and cannot have content.

<svelte:window>

基本上就是在一開始的時候 window 還不存在,如果你想對 window 做事就可以依靠這個元素,可以在上面綁事件,或是得到一些資訊:

  • innerWidth
  • innerHeight
  • outerWidth
  • outerHeight
  • scrollX
  • scrollY
  • online: 的別名window.navigator.onLine

然而上面只有 scrollXscrollY 可以操作,其他都是唯讀的(單純取值)。

下面用一個簡單的範例,雖然沒做什麼特別的事。

<script lang="ts">
    let y: number;
    let height: number;
</script>

<svelte:window
    bind:scrollY={y}
    bind:innerHeight={height}
    on:click={() => console.log('click window')}
/>

<div>y: {y}</div>
<div>height: {height}</div>

另外也要注意,svelte:window 這個元素只能出現在頂層,雖然我想應該也沒人會把他用其他東西包起來吧


<svelte:document>

svelte:window 很像,只是操作對象變成 document,一樣只能放在頂層。

然後官方有提醒到說不要在上面綁 mouseentermouseleave 之類的,因為可能不會在所有瀏覽器中運作,如果要使用請看下一個 <svelte:body>


<svelte:body>

老樣子,只是操作對象變成 body


<svelte:head>

雖然很想直接說跟上面都很像,不過因為 head 應該是比較常會出現的東西(?),在你要改 head 的時候非常方便,例如 titlemeta 之類的,React 還要裝套件來做這件事,Svelte直接幫你搞定。


<svelte:options>

這個是修改一些編譯器的設定(以組件為範圍),因為選項有很多,所以先偷懶一下


<svelte:fragment>

終於到了最後一個,這個很單純,就類似 Vue 當中的 <template>,或者是 React 當中的 <React.Fragment><></>,總之就是可以包住一堆元素,然後不會把自己呈現出來(只呈現包住的東西)的元素。

但是這邊比較特別的是他只允許被放在子組件下面,也就是幫忙 <slot> 這個標籤。

例如: Box.svelte

<div>
    <slot />
</div>

然後可以這樣使用:

<script lang="ts">
    import Box from '../components/Box.svelte';
</script>

<Box>
    <svelte:fragment>
        <div>1</div>
        <div>2</div>
        <div>3</div>
    </svelte:fragment>
</Box>

他就不會多呈現一層東西在外層,雖然如果你是要不影響排版,也可以純粹透過 CSS 做到這件事,不見得要透過這個特殊元素,如果你比賽忘記還有救

然後他也是可以指定要補哪個 slot 的:

<svelte:fragment slot="header">
    <div>Header</div>
</svelte:fragment>

總結

這次一篇把 Svelte 提供的特殊元素介紹了一遍,除了中間偷懶了一個

常用的應該就那些,反正忘了再去翻一下就好,至少知道有提供這些功能。




最後更新時間: 2023年04月18日.