前端新寵 Svelte 帶來哪些新思想?趕緊學起來!
Svelte[1] 是我用過最爽的框架,就算 Vue 和 React 再強大,生態再好,我還是更喜歡 Svelte,因為它開發起來真的很爽。
其實在很久之前我就注意到 Svelte[2] ,但一直沒把這個框架放在心上。
因為我之前的工作主要使用 Vue,偶爾也會接觸到一些 React 專案,但完全沒遇到過使用 Svelte 的項。
直到 Vite 的出現,我才開始開始重視 Svelte。
從 Vite文件[3] 裡可以看到它支援這些模板:
JavaScript |
TypeScript |
vanilla [4] |
vanilla-ts [5] |
vue [6] |
vue-ts [7] |
react [8] |
react-ts [9] |
preact [10] |
preact-ts [11] |
lit [12] |
lit-ts [13] |
svelte [14] |
svelte-ts [15] |
能讓祖師爺也重視的框架,不簡單不簡單~
我喜歡用 Demo 的方式學習新技術,Svelte 官方入門教程[16] 就提供了這種方式。
這是我覺得入門比較舒服且方便日後搜尋的學習方式。
雖然 Svelte 官方入門教程[17] 已經給出很多例子,而且 Svelte中文網[18] 也有對應的翻譯,但有些翻譯看上去是機譯,而且部分案例可能不太適合新手學習~
本文的目的是把 Svelte 的學習流程梳理出來,讓第一次接觸 Svelte 的工友能順利上手。
**本文適合人群:有 HTML 、CSS 、JS 基礎,知道並已經安裝了 Node**。
如果你是打算從0開始學習前端,那本文暫時還不適合你閱讀。
Svelte 簡介
- Svelte[19] 是一個構建 web 應用程式的工具。
- 傳統框架如 React 和 Vue 在瀏覽器中需要做大量的工作,而 Svelte 將這些工作放到構建應用程式的編譯階段來處理。
需要注意,Svelte 是一款編譯器。它可以將按照規定語法編寫的程式碼打包成瀏覽器能執行的專案。
和其他前端框架一樣,同樣也是使用 HTML 、CSS 和 JavaScript 進行開發。
作者
在學習 Svelte 之前先了解一下它的父親(作者)。
Svelte 的作者叫 Rich Harris[20] ,正在吃東西的這位就是他。
01.jpg
可能國內大多數工友對他不是很熟悉(我也完全不熟),但應該聽過 Rollup[21] 。
沒錯,他也是 Rollup[22] 的爸爸。
他在開發 Svelte 之前還開發過 Ractive.js[23] ,聽說 Vue 的部分實現也是受到了 Ractive 的啟發。
關於 Rich Harris 的介紹還有很多,我搜到的資料上這樣介紹到:
大學專業是學哲學的
在紐約時報調查組工作的圖形編輯,身兼記者和開發者職位
還有更多關於他和 Svelte 的介紹,可以看看 《Svelte \- The magical disappearing UI framework \- Interview with Rich Harris》[24]
Svelte 的優勢
Svelte 翻譯成中文就是“苗條”的意思,側面表明它打包出來的包非常小。
Svelte 主要優勢有以下幾點。
1). 編譯器
在開啟Svelte官網[25]時就能看到這樣的介紹。
Svelte 是一種全新的構建使用者介面的方法。傳統框架如 React 和 Vue 在瀏覽器中需要做大量的工作,而 Svelte 將這些工作放到構建應用程式的編譯階段來處理。
Svelte 元件需要在 .svelte 字尾的檔案中編寫,Svelte 會將編寫好的程式碼翻編譯 JS 和 CSS 程式碼。
2). 打包體積更小
Svelte 在打包會將引用到的程式碼打包起來,而沒引用過的程式碼將會被過濾掉,打包時不會加入進來。
在 《A RealWorld Comparison of Front-End Frameworks with Benchmarks \(2019 update\)》[26] 報告中,對主流框架進行了對比。
02.png
在經過 gzip 壓縮後生成的包大小,從報告中可以看出,Svelte 打包出來的體積甩開 Vue、React 和 Angular 幾條街。
這是因為經過 Svelte 編譯的程式碼,僅保留引用到的部分。
3). 不使用 Virtual DOM
Virtual DOM 就是 虛擬DOM,是用 JS 物件描述 DOM 節點的資料,由 React 團隊推廣出來的。
虛擬DOM 是前端的網紅,因此也有很多開發者開始研究和搞辯論賽。
網上有一張圖對比了 Svelte 和 React 在資料驅動檢視的流程
03.png
其實主要對比了使用虛擬DOM和直接操作真實DOM的區別。
在 React 中實現資料驅動檢視大概流程是這樣的:
資料發生變化 -> 通過diff演算法判斷要更新哪些節點 -> 找到要更新的節點 -> 更新真實DOM 複製程式碼
Vue 的資料更新原理其實也差不多,只是實現方式和使用語法會有所不同。
diff演算法 會根據資料更新前和更新後生成的虛擬DOM進行對比,只有兩個版本的虛擬DOM存在差異時,才會更新對應的真實DOM。
使用虛擬DOM對比的方式會比直接對比真實DOM的效率高。
而且真實DOM身上掛載的屬性和方法非常多,使用虛擬DOM的方式去描述DOM節點樹會顯得更輕便。
但這也意味著每次資料發生變化時都要先建立一個虛擬DOM,並使用 diff演算法 將新虛擬DOM與舊虛擬DOM進行比對,這個步驟會消耗一點效能和需要一點執行時間。
而 Svelte 在未使用虛擬DOM的情況下實現了響應式設計。
我以粗暴的方式理解:Svelte 會監聽頂層元件所有變數,一旦某個變數發生變化,就更新使用過該變數的元件。這就僅僅只需更新受影響的那部分DOM元素,而不需要整個元件更新。
綜上所述,在我的理解力,虛擬DOM的思想很優秀,也是順應時代的產物,但虛擬DOM並不是最快的,JS 直接操作 DOM 才是最快。
《Virtual DOM is pure overhead》[27] 是 Svelte 官網上的一篇部落格,專門討論虛擬DOM。有興趣的工友可以看看~
4). 更自然的響應式
這也是我剛接觸 Svelte 時立刻喜歡上的理由。
這裡說的響應式設計是隻關於資料的響應,而不是像 Bootstrap 的響應式佈局。
現在流行的前端框架基本都使用 資料驅動檢視 這個概念,像 Vue 和 React 這些框架,都有響應式資料的概念。
但 Vue 和 React 在資料響應方面還是有點“不那麼自然”,我簡單舉幾個例子:
- 在 React 中,如果需要更新資料並在檢視中響應,需要使用 setState 方法更新資料。
- 在 Vue2 中,響應式資料要放在 data 裡,在 methods 中使用 this.xxx 來更新資料。
- 在 Vue3 的 Composition API 語法中,需要使用 ref 或者 reactive 等方法包裹資料,使用 xxx.value 等方式修改資料。
上面這幾種情況,感覺多少都添加了點東西才能實現響應式資料功能(至少在普通開發者開發時是這樣)。
在 Svelte 的理念中,響應式應該給開發者一種無感體驗,比如在 Excel 中,當我規定 C1 單元格的值是 A1 + B1 的和,設定好規則後,使用者只需要修改 A1 和 B1 即可,C1 會自動響應,而不需再做其他操作。
04.gif
在這方面,Svelte 我認為在現階段是做得最自然的。
05.gif
<h1>{name}</h1> <script> let name = '雷猴' setTimeout(() => { name = '鯊魚辣椒' }, 1000) </script> 複製程式碼
上面的程式碼中,1秒後修改 name 的值,並更新檢視。
從程式碼就能看出,在使用 Svelte 開發專案時,開發者一般無需使用額外的方法就能做到和 Vue、React 的響應式效果。
如果你對 Svelte 響應式原理感興趣,推薦閱讀 FESKY[28] 的 《Svelte 響應式原理剖析 —— 重新思考 Reactivity》[29]
也可以看看 《Rethinking reactivity》[30],看看官方對 reactivity 的思考。
5). 效能強
Stefan Krause 給出一份 效能測試報告(點選可檢視)[31] 對比裡多個熱門框架的效能。從 Svelte 的效能測試結果可以看出,Svelte 是相當優秀的。
6). 記憶體優化
效能測試報告(點選可檢視)[32] 也列出不同框架的記憶體佔用程度,Svelte 對記憶體的管理做到非常極致,佔用的記憶體也是非常小,這對於配置不高的裝置來說是件好事。
第5和6點,由於測試報告比較長,我沒截圖放進文中。大家有興趣可以點開連結檢視測試報告[33]。
7). 更關注無障礙體驗
在使用 Svelte 開發時會 自動對無障礙訪問方面的體驗進行檢測,比如 img 元素沒有新增 alt 屬性,Svelte 會向你發出一條警告。無障礙體驗對特殊人事來說是很有幫助的,比如當你在 img 標籤中設定好 alt 屬性值,使用有聲瀏覽器會把 alt 的內容讀出來。
在此我還要推薦2本關於設計體驗的書。
- 《點石成金:訪客至上的Web和移動可用性設計祕笈》
- 《包容性Web設計》
它們的封面長分別這個樣子
06.jpg
07.jpg
Svelte 的優勢肯定還有很多,但由於我開發經驗不足,只能總結出以上這些了。如果你對 Svelte 有更多理解,歡迎在評論區補充~
Svelte 的不足
- Svelte 對 IE 是非常不友好的,但我並不把這放在眼裡。如果想相容 IE 我還是推薦使用 jQuery。
- Svelte 的生態不夠豐富。由於是“新寵”,生態方面肯定是不如 Vue 和 React 的。
與 Svelte 相關的庫
Sapper
Sapper 官網地址[34]
Sapper 是構建在 Svelte 上的框架,Sapper 提供了頁面路由、佈局模板、SSR等功能。
Svelte Native
Svelte Native 官網地址[35]
Svelte Native 是建立在 NativeScript[36] 之上的產物,可以開發安卓和iOS應用,是一個跨端技術。
有點類似於 React Native 和 Weex 之類的東西。
svelte-gl
svelte-gl 倉庫[37]
svelte-gl 還沒正式釋出,但這是個很有趣的工具,它和 three.js[38] 類似,專門做 3D應用的。
雖然現在 github 上的 Star 還不是很多,但也可以寫些 demo 玩玩。
建立專案
在開始之前,你需要在電腦上安裝 Node[39] 環境。
編輯工具我使用了 VS Code ,同時安裝了 Svelte for VS Code 擴充套件外掛[40] 。
使用 Svelte 前,必須有一個開發環境。
建立或使用開發環境有以下幾種方式:
- REPL
- Rollup 版
- Webpack 版
- Parcel 版
- Vite 版
本文使用的是 Vite 建立專案,但上面列出的所有方式我都會逐一說說。
REPL
REPL 是 Svelte 提供的一個線上環境,開啟 Svelte 官網[41] 可以看到頂部導航欄上面有個 REPL[42] 的選項。點選該選項就可以跳轉到 Svelte 線上開發環境了。
08.png
09.png
REPL 是 read(讀取)、evaluate(執行)、print(列印) 和 loop(迴圈) 這幾個單詞的縮寫。
如果你只是想嘗試 Svelte 的某些功能或者測試小型程式碼,可以使用這款線上工具。
REPL 還提供了多元件開發,按左上角的 +號 可以建立新元件。元件的內容稍後會說到。
介面右側,頂部有3個選項:
- Result: 執行結果。
- JS output: Svelte 編譯後的 JS 程式碼。
- CSS output: Svelte 編譯後的 CSS 程式碼。
10.png
在 REPL 介面右上角還有一個下載按鈕。
11.png
當你在線上環境寫好程式碼,可以點選下載按鈕把專案儲存到本地,下載的檔案是一個 zip,需要自己手動解壓。
然後使用以下命令初始化專案並執行即可。
# 1、初始化專案 npm install # 2、執行專案 npm run dev # 3、在瀏覽器訪問 http://localhost:5000 複製程式碼
執行結果:
12.png
Rollup 版
Svelte 官方也提供了一個命令,可以下載 Svelte 專案到本地。
命令最後需要輸入你的專案名稱。
# 1、下載模板 npx degit sveltejs/template 專案名稱 # 2、安裝依賴 npm install # 3、執行專案 npm run dev # 4、在瀏覽器訪問 http://localhost:8080 複製程式碼
執行結果:
13.png
這是官方提供的建立專案方式,這個專案是使用 Rollup 打包的。
Rollup 和 Svelte 都是同一個作者(Rich Harris[43] )開發的,用回自家東西很正常。
Webpack 版
如果你不想使用 Rollup 打包專案,可以嘗試使用 Webpack。
# 1、下載模板 npx degit sveltejs/template-webpack 專案名稱 # 2、安裝依賴 npm install # 3、執行專案 npm run dev # 4、在瀏覽器訪問 http://localhost:8080/ 複製程式碼
執行結果:
14.png
Parcel 版
我並 不推薦使用 該方法建立專案,因為 Svelte 並沒有提供使用 Parcel 打包工具的模板。但 GitHub 上有第三方的解決方案(點選訪問倉庫)[44]。
將 DeMoorJasper/parcel-plugin-svelte[45] 的程式碼下載下來。
# 1、進入 `packages/svelte-3-example` 目錄 # 2、安裝依賴 npm install # 3、執行專案 npm run start # 4、在瀏覽器訪問 http://localhost:1234/ 複製程式碼
執行結果:
15.png
Vite 版
本文接下來所有例子都是使用 Vite 建立 Svelte 專案進行開發的。
使用 Vite 建立專案的原因是:快!
# 1、下載模板的命令 npm init vite@latest # 2、輸入專案名 # 3、選擇 Svelte 模板(我沒選ts) # 4、進入專案並安裝依賴 npm install # 5、執行專案 npm run dev # 6、在瀏覽器訪問 http://127.0.0.1:5173/ 複製程式碼
執行結果:
16.png
本文使用 Vite 建立專案,目錄結構和 Rollup版 創建出來的專案結構稍微有點不同,但開發邏輯是一樣的。
起步
index.html 、src/main.js 和 src/App.svelte 這三個是最主要的檔案。
index.html 是專案執行的入口檔案,它裡面引用了 src/main.js 檔案。
src/main.js 裡引入了 src/App.svelte 元件,並使用以下程式碼將 src/App.svelte 的內容渲染到 #app 元素裡。
const app = new App({ target: document.getElementById('app') }) 複製程式碼
target 指明目標元素。
我們大部分程式碼都是寫在 .svelte 字尾的檔案裡。
.svelte 檔案主要保安 多個 HTML 元素、1個 script 元素 和 1個 style 元素 。這3類元素都是可選的。
我們主要的工作目錄是 src 目錄。
為了減輕學習難度,我們先做這幾步操作。
1、清空全域性樣式
如果你使用 Rollup版 建立專案,不需要做這一步。
在使用 Vite 建立的 Svelte 專案中,找到 src/app.css 檔案,並把裡面的內容清空掉。
2、改造 src/App.svelte
將 src/App.svelte 檔案改成以下內容
<script> let name = '雷猴' function handleClick() { name = '鯊魚辣椒' } </script> <div>Hello {name}</div> <button on:click={handleClick}>改名</button> 複製程式碼
此時點選按鈕,頁面上的 “雷猴” 就會變成 “鯊魚辣椒”
17.gif
上面的程式碼其實和 Vue 有點像。
- 變數和方法都寫在 <script> 標籤裡。
- 在 HTML 中使用 {} 可以繫結變數和方法。
- 通過 on:click 可以繫結點選事件。
只需寫以上程式碼,Svelte 就會自動幫我們做資料響應的操作。一旦資料發生改變,檢視也會自動改變。
是不是非常簡單!
基礎模板語法
Svelte 的模板語法其實和 Vue 是有點像的。如果你之前已經使用過 Vue,那本節學起來就非常簡單。
插值
在 “起步章節” 已經使用過 插值 了。在 Svelte 中,使用 {} 大括號將 script 裡的資料繫結到 HTML 中。
18.png
<script> let name = '雷猴' </script> <div>{name}</div> 複製程式碼
此時頁面上就會出現 name 的值。
這種語法和 Vue 是有點像的,Vue 使用雙大括號的方式 {{}} 繫結資料。Svelte 就少一對括號。
表示式
在 HTML 中除了可以繫結變數外,還可以繫結表示式。
19.png
<script> let name = '雷猴' function sayHi() { return `${name} 世界!` } let a = 1 let b = 2 let state = false </script> <div>{sayHi()}</div> <div>{a} + {b} = {a + b}</div> <div>{state ? '雷猴' : '鯊魚辣椒'}</div> 複製程式碼
屬性繫結
HTML 的屬性需要動態繫結資料時,也是使用 {} 語法。
20.png
<script> let name = '雷猴' </script> <div title={name}>Hello</div> 複製程式碼
當滑鼠放到 div 標籤上時,會出現 title 裡的提示資訊。
渲染 HTML 標籤 @html
如果只是使用插值的方法渲染帶有 HTML 標籤的內容,Svelte 會自動轉義 < 、> 之類的標籤。
21.png
<script> let h1El = '<h1 style="color: pink;">雷猴</h1>' </script> <div>{h1El}</div> 複製程式碼
這種情況多數出現在渲染富文字。
在 Vue 中有 v-html 方法,它可以將 HTML 標籤渲染出來。在 Svelte 中也有這個方法,在插值前面使用 @html 標記一下即可。
22.png
<script> let h1El = '<h1 style="color: pink;">雷猴</h1>' </script> <div>{@html h1El}</div> 複製程式碼
但此方法有可能遭受 XSS 攻擊。
我在 《NodeJS 防止xss攻擊》[46] 中簡單演示過 XSS 攻擊,有興趣的可以看看。
樣式繫結
在日常開發中,給 HTML 標籤設定樣式主要通過 行內 style 和 class 屬性。
基礎的 HTML 寫法和原生的一樣,這裡不過多講解。
下面主要講動態設定樣式,也就是將 JS 裡的變數或者表示式繫結到 style 或者 class 裡。
行內樣式 style
23.gif
<script> let color = 'red' setTimeout(() => { color = 'blue' }, 1000) </script> <div style="color: {color}">雷猴</div> 複製程式碼
1秒後,文字從紅色變成藍色。
繫結 class
24.gif
<script> let foo = true setTimeout(() => { foo = false }, 1000) </script> <div class:active={foo}>雷猴</div> <style> .active { color: red; } </style> 複製程式碼
在 HTML 裡可以使用 class:xxx 動態設定要啟用的類。這裡的 xxx 是對應的類名。
語法是 class:xxx={state} ,當 state 為 true 時,這個樣式就會被啟用使用。
條件渲染 #if
使用 {#if} 開頭,{/if} 結尾。
基礎條件判斷
{#if 條件判斷} ... {/if} 複製程式碼
舉個例子
25.gif
<script> let state = true setTimeout(() => { state = false }, 1000) </script> {#if state} <div>雷猴</div> {/if} 複製程式碼
1秒後改變狀態
兩種條件
{#if 條件判斷} ... {:else} ... {/if} 複製程式碼
舉個例子
26.gif
<script> let state = true setTimeout(() => { state = false }, 1000) </script> {#if state} <div>雷猴</div> {:else} <div>鯊魚辣椒</div> {/if} 複製程式碼
多種條件
{#if 條件判斷} ... {:else if 條件判斷} ... {/if} 複製程式碼
舉個例子
27.gif
<script> let count = 1 setInterval(() => { count++ }, 1000) </script> {#if count === 1} <div>雷猴</div> {:else if count === 2} <div>鯊魚辣椒</div> {:else} <div>蟑螂惡霸</div> {/if} 複製程式碼
條件渲染的用法比較簡單,只要 JS 基礎就能看得懂。
列表渲染 #each
如果你有一堆資料需要展示出來,可以使用 #each 方法。
使用 {#each} 開頭,{/each} 結尾。
遍歷陣列
{#each expression as name} ... {/each} 複製程式碼 舉個例子
28.png
<script> let list = ['a', 'b', 'c', 'd', 'e', 'f'] </script> <ul> {#each list as item} <li>{item}</li> {/each} </ul> 複製程式碼
要注意,Svelte 和 Vue 的遍歷在寫法上有點不同。
Vue的方式是:
<div v-for="元素 in 源資料"> <span>{{元素}}</span> </div> 複製程式碼
Svelte的方式是:
<div> {#each 源資料 as 元素} <span>{元素}</span> {/each} </div> 複製程式碼
遍歷陣列(帶下標)
29.png
<script> let list = ['a', 'b', 'c', 'd', 'e', 'f'] </script> <ul> {#each list as item, index} <li>{index} -- {item}</li> {/each} </ul> 複製程式碼
注意:as 後面首先跟著元素,然後才是下標。而且元素和下標不需要用括號括起來。
如果元素是物件,可以解構
30.png
<script> let list = [ {name: '雷猴'}, {name: '鯊魚辣椒'} ] </script> <ul> {#each list as {name}} <li>{name}</li> {/each} </ul> 複製程式碼
預設內容
如果源資料沒有內容,是空陣列的情況下,還可以組合 {:else} 一起使用。
31.png
<script> let list = [] </script> <div> {#each list as {name}} <div>{name}</div> {:else} <div>暫無資料</div> {/each} </div> 複製程式碼
事件繫結 on:event
使用 on: 指令監聽 DOM 事件,on: 後面跟隨事件型別
語法:
on:事件型別={事件名} 複製程式碼
舉個例子,點選按鈕時在控制檯輸出 “雷猴”。
32.gif
<script> function sayHi() { console.log('雷猴') } </script> <button on:click={sayHi}>打招呼</button> 複製程式碼
繫結其他事件(比如change等)也是同樣的道理。
事件修飾符
如果你只希望某些事件只執行一次,或者取消預設行為,或者阻止冒泡等,可以使用事件修飾符。
語法:
on:事件型別|修飾符={事件名} 複製程式碼
舉個例子,我希望點選事件只能執行一次,之後再點選都無效,可以使用官方提供的 once 修飾符。
33.gif
<script> function sayHi() { console.log('雷猴') } </script> <button on:click|once={sayHi}>打招呼</button> 複製程式碼
從上圖可以看出,多次點選都只是輸出1次“雷猴”。
除了 once 之外,還有以下這些修飾符可以用:
- preventDefault :禁止預設事件。在程式執行之前呼叫 event.preventDefault()
- stopPropagation :呼叫 event.stopPropagation(), 防止事件到達下一個標籤
- passive :改善了 touch/wheel 事件的滾動表現(Svelte會在合適的地方自動加上它)
- capture:表示在 _capture_階段而不是_bubbling_觸發其程式
- once :程式執行一次後刪除自身
串聯修飾符
修飾符還可以串聯起來使用,比如 on:click|once|capture={...}
但需要注意,有些特殊的標籤使用修飾符會出現“意想不到”的結果,比如 <a> 標籤。
34.gif
本來是想給 <a> 標籤繫結一個點選事件,第一次點選時在控制檯輸出一句話,並且禁止 <a> 標籤的預設事件。
所以使用了 once 和 preventDefault 修飾符。
但實際上並非如此。上面的程式碼意思是 once 設定了只執行一次 toLearn 事件,並且只有一次 preventDefault 是有效的。
只有點選時就不觸發 toLearn 了,而且 preventDefault 也會失效。所以再次點選時,<a> 元素就會觸發自身的跳轉功能。
資料繫結 bind
資料繫結通常會和表單元素結合使用。
bind 可以做到雙向資料繫結的效果。我覺得 Svelte 裡的 bind 有點像 Vue 的 v-model。
語法:
bind:property={variable} 複製程式碼
input 單行輸入框
35.gif
<script> let msg = 'hello' function print() { console.log(msg) } </script> <input type="text" value={msg} /> <button on:click={print}>列印</button> 複製程式碼
如果只是使用 value={msg} 的寫法,input 預設值是 hello ,當輸入框的值發生改變時,並沒有把內容反應回 msg 變數裡。
此時就需要使用 bind 了。
36.gif
<!-- 省略部分程式碼 --> <input type="text" bind:value={msg} /> 複製程式碼
textarea 多行文字框
多行文字框同樣繫結在 value 屬性上。
37.gif
<script> let msg = 'hello' </script> <textarea type="text" bind:value={msg} /> <p>{msg}</p> 複製程式碼
input range 範圍選擇
因為都是 input 元素,只是 type 不同而已。所以範圍選擇元素同樣需要繫結 value 。
38.gif
<script> let val = 3 </script> <input type="range" bind:value={val} min=0 max=10 /> <p>{val}</p> 複製程式碼
radio 單選
單選框通常是成組出現的,所以要繫結一個特殊的值 bind:grout={variable}
39.gif
<script> let selected = '2' </script> <input type="radio" bind:group={selected} value="1" /> <input type="radio" bind:group={selected} value="2" /> <input type="radio" bind:group={selected} value="3" /> <p>{selected}</p> 複製程式碼
checkbox 複選框
40.gif
<script> let roles = [] </script> <input type="checkbox" bind:group={roles} value="雷猴" /> <input type="checkbox" bind:group={roles} value="鯊魚辣椒" /> <input type="checkbox" bind:group={roles} value="蟑螂惡霸" /> <input type="checkbox" bind:group={roles} value="蠍子萊萊" /> <p>{roles}</p> 複製程式碼
select 選擇器
41.gif
<script> let selected = 'a' </script> <select bind:value={selected}> <option value='a'>a</option> <option value='b'>b</option> <option value='c'>c</option> </select> <span>{selected}</span> 複製程式碼
select multiple 選擇器
multiple 和 checkbox 有點像。
42.gif
<script> let selected = [] </script> <select multiple bind:value={selected}> <option value="雷猴">雷猴</option> <option value="鯊魚辣椒">鯊魚辣椒</option> <option value="蟑螂惡霸">蟑螂惡霸</option> <option value="蠍子萊萊">蠍子萊萊</option> </select> <span>{selected}</span> 複製程式碼
簡寫形式
如果 bind 繫結的屬性和在 JS 裡宣告的變數名相同,那可以直接繫結
43.gif
<script> let value = 'hello' </script> <input type="text" bind:value /> <p>{value}</p> 複製程式碼
這個例子中,bind:value 繫結的屬性是 value ,而在 JS 中宣告的變數名也叫 value ,此時就可以使用簡寫的方式。
$: 宣告反應性
- 通過使用$: JS label 語法[47]作為字首。可以讓任何位於 top-level 的語句(即不在塊或函式內部)具有反應性。每當它們依賴的值發生更改時,它們都會在 component 更新之前立即執行。
上面這段解釋是官方文件的解釋。
$: 在文件中稱為 Reactivity ,中文文件成它為 反應效能力。
但我使用 $: 時,覺得這個功能有點像 Vue 的 computed。
$: 可以監聽表示式內部的變化從而做出響應。
44.gif
<script> let count = 0; $: doubled = count * 2; function handleClick() { count += 1; } </script> <button on:click={handleClick}> 點選加1 </button> <p>{count} 翻倍後 {doubled}</p> 複製程式碼
使用 $: 宣告的 double 會自動根據 count 的值改變而改變。
如果將以上程式碼中 $: 改成 let 或者 var 宣告 count ,那麼 count 將失去響應性。
這樣看來,真的和 Vue 的 computed 的作用有那麼一點像。
非同步渲染 #await
Svelte 提供非同步渲染標籤,可以提升使用者體驗。
語法:
{#await expression} ... {:then name} ... {:catch name} ... {/await} 複製程式碼
以 #await 開始,以 /await 結束。
:then 代表成功結果,:catch 代表失敗結果。
expression 是判斷體,要求返回一個 Promise。
其實用法和 #if ... :else if ... /if 有那麼一丟丟像。
舉個例子
45.gif
<script> const api = new Promise((resolve, reject) => { setTimeout(() => { resolve('請求成功,資料是xxxxx') }, 1000) }) </script> {#await api} <span>Loading...</span> {:then response} <span>{response}</span> {:catch error} <span>{error}</span> {/await} 複製程式碼
如果將上面的 resolve 改成 reject 就會走 :catch 分支。
基礎元件
在 Svelte 中,建立元件只需要建立一個 .svelte 為字尾的檔案即可。
通過 import 引入子元件。
比如,在 src 目錄下有 App.svelte 和 Phone.svelte 兩個元件。
App.svelte 是父級,想要引入 Phone.svelte 並在 HTML 中使用。
46.png
App.svelte
<script> import Phone from './Phone.svelte' </script> <div>子元件 Phone 的內容:</div> <Phone /> 複製程式碼
Phone.svelte
<div>電話:13266668888</div> 複製程式碼
元件通訊
元件通訊主要是 父子元件 之間的資料來往。
父傳子
比如上面的例子,手機號希望從 App.svelte 元件往 Phone.svelte 裡傳。
可以在 Phone.svelte 中宣告一個變數,並公開該變數。
App.svelte 就可以使用對應的屬性把值傳入。
47.png
App.svelte
<script> import Phone from './Phone.svelte' </script> <div>子元件 Phone 的內容:</div> <Phone number="88888888" /> 複製程式碼
Phone.svelte
<script> export let number = '13266668888' </script> <div>電話:{number}</div> 複製程式碼
如果此時 App.svelte 元件沒有傳值進來,Phone.svelte 就會使用預設值。
子傳父
如果想在子元件中修改父元件的內容,需要把修改的方法定義在父元件中,並把該方法傳給子元件呼叫。
同時需要在子元件中引入 createEventDispatcher 方法。
48.gif
App.svelte
<script> import Phone from './Phone.svelte' function print(data) { console.log(`手機號: ${data.detail}`) } </script> <div>子元件 Phone 的內容:</div> <Phone on:printPhone={print} /> 複製程式碼
Phone.svelte
<script> import { createEventDispatcher } from 'svelte' const dispatch = createEventDispatcher() function printPhone() { dispatch('printPhone', '13288888888') } </script> <button on:click={printPhone}>輸出手機號</button> 複製程式碼
父元件接受引數是一個物件,子元件傳過來的值都會放在 detail 屬性裡。
插槽 slot
和 Vue 一樣,Svelte 也有元件插槽。
在子元件中使用 <slot> 標籤,可以接收父元件傳進來的 HTML 內容。
49.png
App.svelte
<script> import Phone from './Phone.svelte' </script> <div>子元件 Phone 的內容:</div> <Phone> <div>電話:</div> <div>13288889999</div> </Phone> 複製程式碼
Phone.svelte
<style> .box { width: 100px; border: 1px solid #aaa; border-radius: 8px; box-shadow: 2px 2px 8px rgba(0,0,0,0.1); padding: 1em; margin: 1em 0; } </style> <div class="box"> <slot>預設值</slot> </div> 複製程式碼
生命週期
生命週期是指專案執行時,指定時期會自動執行的方法。
Svelte 中主要有以下幾個生命週期:
- onMount: 元件掛載時呼叫。
- onDestroy: 元件銷燬時執行。
- beforeUpdate: 在資料更新前執行。
- afterUpdate: 在資料更新完成後執行。
- tick: DOM元素更新完成後執行。
以上生命週期都是需要從 svelte 裡引入的。
用 onMount 舉個例子
50.gif
<script> import { onMount } from 'svelte' let title = 'Hello world' onMount(() => { console.log('onMount') setTimeout(() => title = '雷猴', 1000) }) </script> <h1>{title}</h1> 複製程式碼
在元件載入完1秒後,改變 title 的值。
onDestroy、beforeUpdate 和 afterUpdate 都和 onMount 的用法差不多,只是執行的時間條件不同。你可以自己建立個專案試試看。
tick 是比較特殊的,tick 和 Vue 的 nextTick 差不多。
在 Svelte 中,tick 的使用語法如下:
import { tick } from 'svelte' await tick() // 其他操作 複製程式碼
總結
本文主要講解了 Svelte 的基礎用法,但 Svelte 的內容和 API 遠不止此。它還有很多高階的用法以及提供了過渡動畫功能等,這些都會放在高階篇講解。
Svelte 是一個 Web 應用的構建工具,它打包出來的專案體積比較小,效能強,不使用虛擬DOM。
但 Svelte 的相容性和周邊生態相比起 Vue 和 React 會差一點。
所以日常專案中需要根據 Svelte 的優缺點進行取捨。
- Spring中實現非同步呼叫的方式有哪些?
- 帶引數的全型別 Python 裝飾器
- 整理了幾個Python正則表示式,拿走就能用!
- SOLID:開閉原則Go程式碼實戰
- React中如何引入CSS呢
- 一個新視角:前端框架們都卷錯方向了?
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 手寫程式語言-遞迴函式是如何實現的?
- 一文搞懂模糊匹配:定義、過程與技術
- 新來個阿里 P7,僅花 2 小時,做出一個多執行緒永動任務,看完直接跪了
- Puzzlescript,一種開發H5益智遊戲的引擎
- @Autowired和@Resource到底什麼區別,你明白了嗎?
- CSS transition 小技巧!如何保留 hover 的狀態?
- React如此受歡迎離不開這4個主要原則
- LeCun再炮轟Marcus: 他是心理學家,不是搞AI的
- Java保證執行緒安全的方式有哪些?
- 19個殺手級 JavaScript 單行程式碼,讓你看起來像專業人士
- Python 的"self"引數是什麼?
- 別整一坨 CSS 程式碼了,試試這幾個實用函式
- 再有人問你什麼是MVCC,就把這篇文章發給他!