Svelte 基本模板語法

tags: Svelte
category: Front-End
description: Svelte 基本模板語法
created_at: 2023/04/01 16:00:00

cover image


回到 手把手開始寫 Svelte


前言

老樣子,假設你已經做好開新專案與環境設定裡面所做的事

這邊對 VueReact 的使用者可能會覺得比較跳一些(?),雖然可能也還好,看過那麼多東西見怪不怪了,看淡就好

Vue 當中模板語法比較像是指令,寫在 HTML tag 上面

React 當中就都是 JavaScript 隨你組

而在 Svelte 會比較像是後端的模板引擎(Template Engine)


本篇會介紹到以下內容

  • 插入變數
  • 插入 html
  • 屬性綁定
  • 定義 style
  • 邏輯相關
    • if 相關
    • 迴圈相關

先從最簡單的開始 - 插入變數

Vue 當中是使用兩個大括號,而這邊會比較像 React,是使用一對大括號包住。

<script>
    let count = 100;
</script>

<div>count is: {count}</div>

包住的也不一定要是變數,主要是 javascript expression

<div>count is: {100 * 2}</div>

插入 html

一般來說基本的大括號包住在任何框架都會有做一些處理,不會真的去 renderhtml(安全性考量),但也會提供方法去讓你直接輸出 html,在必要的時候可以使用。

<script>
    let html = `
        <div>count is: {100 * 2}</div>
    `;
</script>

{html}

你會發現畫面上呈現出 <div>count is: {100 * 2}</div>,而不是預期中的結果。

要輸出 html 的話,要改成下面這樣

<script>
    let htmlString = `
        <div>count is: {100 * 2}</div>
    `;
</script>

{@html htmlString}

但這時你會發現兩個問題

  • 我的 VSCode 報錯,{@html} can lead to XSS attack.
    • 這代表你的 eslint 很乖
    • 只是建議你不要這樣寫,當然你也可以去關設定讓他不要跳這個提醒
  • 畫面上顯示 count is: {100 * 2} 而不是 count is: 200
    • 這是因為 svelte 在你使用 html 輸出的時候,不會幫你做任何處理,就直接輸出

總之盡量不要這樣寫,除非你很清楚你在幹嘛


屬性綁定

屬性綁定的部分就跟 React 比較像了,在 Vue 是使用 :屬性="",來綁定,例如

<div :class="classes" />

而在 Svelte 則是比較像 React,如下:

<script>
    let classes = 'bg-blue-500 text-white';
</script>

<div class={classes}>Hi</div>

Svelte 還有提供一個語法糖,如果你的變數剛好跟屬性名稱一樣,可以簡寫,如下

<script>
    let src = 'https://picsum.photos/200/300';
    let alt = 'Image';
</script>

<img {src} {alt} />

定義 style

Svelte 的單個檔案中也可以定義 style ,這點跟 Vue 比較像,而且他的 style 都是 scope 的,不會去汙染到其他的元件,會比較像 Vue<style scoped></style>

雖然還沒講到組件,不過就先照貼吧(?)

建立檔案: /src/components/Child.svelte

<div>Child</div>

<style>
    div {
        color: blue;
    }
</style>

然後在你的 /src/routes/+page.svelte 貼上:

<script>
    import Child from '../components/Child.svelte';
</script>

<div>Root</div>
<Child />

<style>
    div {
        color: red;
    }
</style>

然後你會看到畫面中兩個 div 的顏色不一樣。


if 相關語法

進到 if 相關的語法了,這邊跟誰都不像,只跟模板引擎像

  • Vue 中,可以簡單透過 v-if 達到
  • React 中,通常透過 ()?():() 或是 () && () 之類的 JavaScript 表達式達到

直接看範例

<script>
    let count = 5;
</script>

{#if count > 0}
    <p>Count is {count}</p>
{/if}

這邊當 count > 0 才會顯示內容,可以為他加入 else,變成以下

<script>
    let count = 0;
</script>

{#if count > 0}
    <p>Count is {count}</p>
{:else}
    <p>Count is zero</p>
{/if}

當然也有 else if 可以用

<script>
    let age = 18;
</script>

{#if age < 18}
    <p>Sorry, you're too young to enter this site.</p>
{:else if age < 65}
    <p>Welcome to the site!</p>
{:else}
    <p>Sorry, you're too old to enter this site.</p>
{/if}

這一段內容是 Copilot 幫我生成的


迴圈相關

老樣子,跟誰都不像,所以直接看範例

<script>
    let products = [
        {
            id: 1,
            name: 'Product 1',
            price: 100
        },
        {
            id: 2,
            name: 'Product 2',
            price: 200
        },
        {
            id: 3,
            name: 'Product 3',
            price: 300
        }
    ];
</script>

{#each products as product}
    <div>
        {product.name}: {product.price}
    </div>
{/each}

應該會看到畫面上呈現

Product 1: 100
Product 2: 200
Product 3: 300

也可以在迴圈的時候拿到 index

{#each products as product, i}
    <div>
        index={i}, {product.name}: {product.price}
    </div>
{/each}

會看到以下

index=0, Product 1: 100
index=1, Product 2: 200
index=2, Product 3: 300

你也可以解構他,少打一點字:

{#each products as { name, price }}
    <div>
        {name}: {price}
    </div>
{/each}

重要的 key 呢?,當然也有

{#each products as { id, name, price } (id)}
    <div>
        {name}: {price}
    </div>
{/each}

那個小括號包起來的就是 key 帶的值

至於不帶 key 會怎樣?,去看Vue3 - 基本的模板語法的最下面,有講到如果不帶 key 會怎樣,還有範例。

而在 Svelte 你不帶,也會發生一樣的事情,總之引用那篇的結論: 講了這麼多,如果不想理解那麼多,總之你就乖乖設 key 為唯一值就對了

最後統整一下 for 的語法,大概會長這樣

{#each 可迭代物件 as 每一個元素, 索引 (key值)}
    <!-- ... -->
{/each}

希望這樣能更幫助理解,總之就是 , 隔開和 空白 隔開: 每一個元素, 索引 (key),按自己需求去寫。


總結

在寫 Svelte 的時候是假設看的人都有其他前端開發經驗了,所以有些地方會跳比較快,而會覺得比較不習慣的可能會是模板的部分(如果沒有寫過任何模板引擎的話),不過反正 IDE 有插件可以幫你寫,或是 Copilot 會幫你補 (?),所以現在應該也不是什麼大問題了。




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