期待已久的新功能,簡單介紹 Svelte 的 Class Attributes

程式技術

如果你跟我一樣是 Tailwind CSS 的愛好者,或是喜歡使用 Utility First 的 CSS 框架,那麼 Svelte 5.16 的新功能「Class Attributes」一定會讓你感到興奮。透過這個新功能,我們能更輕鬆的根據不同條件來動態調整樣式,進而提升開發效率。接下來就讓我來簡單的說明一下,為什麼這個新功能讓我如此期待吧。

根據條件動態調整 class 屬性

在寫 Svelte 時,一定會遇到一個很常見的情況,就是「根據條件動態調整 class 屬性」。簡單舉個例子,點擊按鈕來切換字串的顏色。

<script lang="ts">
    let isError = $state(false);

    function toggleError() {
        isError = !isError;
    }
</script>

<!-- 當按鈕被點擊時,會根據 isError 的值來調整 <p> 的 class 屬性 -->
<p class={isError ? 'text-red-500' : 'text-green-500'}>
	Status
</p>

<button
    type="button"
    onclick={toggleError}
>
    I'm a button
</button>

這裡使用三元運算子來動態調整 <p>class 屬性,當 isError 的值是 true 時,<p>class 屬性為 text-red-500,反之則為 text-green-500

這個寫法看起來很 OK,沒有什麼太大的問題,但如果 <p>class 屬性預設一定會有一個 font-bold 呢?這個時候就需要改一下寫法,將大括號放在雙引號中,並在雙引號裡面加上一個 font-bold

<!-- 錯誤寫法,相同的屬性不能重複 -->
<p 
    class={isError ? 'text-red-500' : 'text-green-500'}
    class="font-bold"
>
	Status
</p>

<!-- 正確寫法 -->
<p
    class="font-bold {isError ? 'text-red-500' : 'text-green-500'}"
>
	Status
</p>

雖然這種寫法也可以,但看起來就不是那麼「優雅」了。在 Svelte 5.16 版本前,你可以使用 class: 語法來改善這種寫法。

class: 語法

在 5.16 版本以前,Svelte 提供 class: 語法來根據條件動態調整 class 屬性。

<p 
    class:text-red-500={isError}
    class:text-green-500={!isError}
    class="font-bold"
>
	Status
</p>

class: 這種寫法相比三元運算子來說會更直觀一些,但緊接著會遇到下一個問題,如果你的 class 屬性不是只有一個樣式呢?例如當 isErrortrue 時,我希望字串除了是紅色的以外,還希望加上其他樣式,例如字體可以更大一點,背景為淡紅色,有紅色邊框,邊框為圓角,邊框距離字串有一點內距。

這個時候使用 class: 的局限性就會出來了,你必須要這樣寫。

<p 
    class:text-red-500={isError}
    class:text-xl={isError}
    class:bg-red-200={isError}
    class:border={isError}
    class:border-red-500={isError}
    class:rounded={isError}
    class:p-2={isError}
    class:text-green-500={!isError}
    class="font-bold"
>
	Status
</p>

除了要一行一行加上想要的樣式,還需要在每個樣式後面加上判斷條件,不得不說這個寫法實在是有點冗長。

Class Attributes

為了改善 class: 的局限性,Svelte 在 5.16 版本推出了 Class Attributes。Class Attributes 允許你在 class 屬性中使用物件與陣列,讓你可以根據條件一次調整多個樣式。

<!-- 物件的寫法 -->
<p 
    class={{
        'text-red-500 text-xl bg-red-200 border border-red-500 rounded p-2': isError,
        'text-green-500': !isError,
        'font-bold': true
    }}
>
	Status
</p>

<!-- 陣列的寫法 -->
<!-- 注意條件式一定要加在前面 -->
<p 
    class={[
        isError && 'text-red-500 text-xl bg-red-200 border border-red-500 rounded p-2',
        !isError && 'text-green-500',
        true && 'font-bold'
    ]}
>
	Status
</p>

我個人比較喜歡物件的寫法,但不論是物件的寫法還是陣列的寫法,相比過去的 class: 寫法都顯得更為簡潔且直觀。這個功能我真的等了好久,謝謝 Svelte 開發團隊帶來這麼棒的新功能 😄!

題外話,Class Attributes 的物件寫法讓我想到了 Laravel Blade 中的 @class 語法,完全可以說是異曲同工啊!

@php
  $inIndexPage = request()->url() === route('posts.index');
@endphp

<a
  href="{{ route('posts.index') }}"
  @class([
      'flex items-center ...',
      'bg-gray-200 text-gray-900 ...' => $inIndexPage,
      'text-gray-500 dark:text-gray-400 ...' => !$inIndexPage,
  ])
  wire:navigate
>
  <x-icon.home class="w-4" />
  <span class="ml-2">全部文章</span>
</a>

參考資料

sharkHead
written by
sharkHead

持續努力中的後端打工仔,在下班後喜歡研究各種不同的技術。稍微擅長 PHP,並偶爾涉獵前端開發。個性就像動態語言般隨興,但渴望做事能像囉嗦的靜態語言那樣嚴謹。

0 則留言
新增留言
編輯留言