期待已久的新功能,簡單介紹 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
屬性不是只有一個樣式呢?例如當 isError
為 true
時,我希望字串除了是紅色的以外,還希望加上其他樣式,例如字體可以更大一點,背景為淡紅色,有紅色邊框,邊框為圓角,邊框距離字串有一點內距。
這個時候使用 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>