這是〈Svelte 從小白到入門〉系列的第一集,各集連結如下:


Svelte 是年輕且發展迅猛的 JS 框架,與 React / Vue 最大的差異是經過 compile 後的 Svelte 元件是以瀏覽器原生的 DOM 操作,省掉了 virtual DOM 這層轉換的開銷,因此在客戶端上執行的效率更高。

本篇是個人整理的 Svelte 學習筆記,內容與範例主要來自於 Svelte Tutorial,但經過適當的簡化與改寫,希望能縮短一半的篇幅的同時傳達出相當的資訊量。

起手式

在 Svelte 的首頁有放開立空白 Svelte 專案的做法,但在這裡我們並不先開立專案,我們使用 Svelte REPL 做為學習的環境,因此起手式超級簡單,只要用瀏覽器開 Svelte REPL 就立馬有個現成可用的 Svelte 環境,在上面註冊帳號後也可以把自己寫的 Svelte 元件存起來。

Svelte 基礎

「Svelte 元件」是構成 Svelte 專案的基礎,也是我們後續撰寫的主要對象,而 Svelte 元件本身是包含了 HTML、CSS、JS 的 .svelte 檔案。

可以把 .svelte 檔案理解為一種被強殖 Svelte 特性的 .html 檔案,裡面有 HTML 標籤與內容,也有 <script> 區塊放元件的程式邏輯,還有 <style> 區塊放元件的樣式。

元件與元件之間是隔離的,彼此不共享元件內的 JS 及 CSS,即便存在於某兩個元件內的 CSS 具有相同的命名,他們在 compile 後也會被重新命名,讓彼此的參照是獨立的,藉此達到隔離的效果,當然 Svelte 也提供了元件與元件之間傳值的機制,並且元件也可以包含另一個子元件,透過這樣重複包裝的巢狀元件,最終構築出一個完整的 web app。

Hello world

第一個元件是老朋友「Hello world!」,在 <script> 區塊內定義的值 name,可以直接在 HTML 內以大括號包圍的格式 {name} 呼叫,因為 name 是字串,也可以在大括號內直接調用 name 的字串函式:

HTML 標籤屬性插值

前面我們把 name 做為內容插入,Svelte 也可以讓我們把值做為 HTML 的屬性插入:

當作屬性插入時,要不要用雙引號包住都是可以的,Svelte 會自動識別與轉換(其實在 HTML 的規範內,是允許省略雙引號的)。

範例內的第三種用法較特別,如果 JS 變數名故意取的和 HTML 屬性名一樣,那就可以用這種簡化的格式,讓我們可以少打幾個字。

巢狀元件

如同在 JS 引入其他套件一般,我們用 import 語句在 App.svelte 元件內引入另一個 Nested.svelte 元件,並且以 <Nested> 的形式在 HTML 內調用:

要注意的是,Svlte 的元件都應該要以大寫開頭的形式命名,避免與 HTML 原生標籤混淆。

另外注意到 App.svelte 內的 <p> 被我們改成紫色,並且這並不影響子元件 Nested.svelte 內的 <p>,這印證了前面說的「元件是互相隔離的」的說法。

內含 HTML 標籤的字串處理

如果 JS 字串內含有 HTML 標籤,基於安全考量,預設的情況下是會被跳脫處理的,也就是會被處理成純文字,如果想要關閉這個特性,那得加上額外的 @html 標示:

該怎麼理解這個 @html?個人是把它理解為一個裝飾器(decorator),然而這只是個人的解讀,在 Svelte 文件內並沒有明確定義 @html 的角色。

Reactivity

在我以前念的化學領域,reactivity 指的是物質的反應性,而在程式領域,reactivity 的華文是「回應式程式設計」,可以簡單的理解為「JS 與 HTML 的連動機制」。

我們可以透過下面的實例感受所謂的 reactivity,按鈕內的 {count} 是隨著 JS 內的 count 而變的,他們之間的連動特性是由 Svelte 提供的,因此我們再也不用手動處理元件的更新:

在上面的例子中:

  • 按鈕與 click 事件是透過 on:click 語句綁定的,這是 Svelte 特有的事件綁定語法,與 HTML 標籤原有的 onclick 屬性相當相似,應該很容易理解,只要記得不要打錯字。
  • 按鈕內的 {count === 1 ? 'time' : 'times'} 僅是一個決定單字單複數形的三元表達式。(零後面到底要跟單數名詞,還是複數名詞?

Reactive Declarations

讓上面的例子再複雜一點,放另一個變數 doubled,並且我們希望這個 doubledcount 的兩倍。

我們可以在 HTML 內加入一個簡單的敘述 {count * 2} 得到兩倍的數值,但若是需要重複調用,那就要無數次的 {count * 2},這不利於未來的重構,為此我們需要另一個 Svelte 特有的語法,以 $: doubled 的形式賦予這個變數 doubled 也具有 reactivity 的特性:

被加上 $: 修飾後的 doubled,會在狀態發生變化時,自動重新執行,所謂的狀態發生變化,以上例來說,就是 handleClick()count 的數值改變。

Reactive Statements

$: 不僅能為變數加上 reactivity 的特性,它也能用於其他的程式敘述,讓該句敘述也能因應狀態變化而再次執行。

下面的範例中,每次點擊都會引發 count 改變,並且我們又用 $: console.log(the count is ${count}); 令這句敘述也會隨著 count 的改變而再次執行:

$: 可以拿來修飾變數、修飾敘述,還可以拿來修飾區塊:

小結

整理一下截至目前為止我們遇到的 Svelte 特有語法:

  • @html:讓內含 HTML 標籤的字串不經過跳脫處理,直接原樣送給瀏覽器 render。
  • on::綁定 HTML 元素的事件行為。
  • $::賦予變數或敘述令其具有 reactivity 的特性。

元件化、資料綁定、事件綁定是每個現代化 web 框架都具有的特性,每個框架實現的方式各異,在這一集我們介紹了 Svelte 在這三方面的用法,多少會有點奇葩之感,然而這些奇葩的語法,未來只會更多,讓我們拭目以待。

(待續)