一、簡單體驗
Svelte 的開發體驗和 Vue 3 很類似
在 Svelte 組件中也是將 JS 寫在 <script> 標籤中,將 CSS 寫在 <style> 中
稍微不同的點在於,DOM 模板不需要寫在 <template> 中,而是可以寫在任何地方
<script>
import Nested from './Nested.svelte';
const title = 'Hello World';
</script>
<style>
p { color: purple; }
</style>
<h1>{title}</h1>
<p>Let's Enjoy Sevelte</p>
<Nested/>
Svelte 中的變量自帶響應式特性,數據變更時會即時渲染到頁面上
同時 Svelte 還提供了 $: 用來實現一段響應式邏輯,就像 Vue 中的 Computed 和 Watch
<script>
let count = 0;
const handleClick = () => count += 1;
$: doubled = count * 2;
$: if (count > 9) {
console.log('count is dangerously high!');
count = 9;
};
</script>
<button on:click={handleClick}>Click</button>
<p>{count} doubled is {doubled}</p>
總之 Svelte 是一個很好上手的框架,更多的特性或語法可以通過官方文檔瞭解,《Svelte 迷途求索》將着重介紹 Svelte 實戰中可能遇到的問題
二、創建 Props:父對子傳參
在開發的時候,如果子組件中的某個數據需要通過父組件傳入,就需要在子組件中聲明 props
// 子組件
<script lang="ts">
export let text: string = undefined;
</script>
<p>hello {text}</p>
沒錯,在 Svelte 中創建 props 就是這麼簡單粗暴,只需要使用 let 創建一個變量,然後通過 export 導出即可
可以給這個 prop 添加一個默認值,不管是上面的 undefined,還是一個具體的值,那麼這個 prop 就會被標記爲可選屬性
如果沒有設置默認值,這個 prop 就是一個必填屬性。使用該組件時如果沒有提供該屬性,則會打印警告
三、通過 prop 傳入函數:子對父傳參
上面已經介紹過,組件的 prop 是通過 let 創建的
而使用 const, class, function 創建的 prop 都是只讀屬性,即使通過 export 導出,也不會接收外部參數
然而通過 prop 傳入一個函數的情況還是挺常見的,比如子組件向父組件傳參
好在雖然不能使用 function,但還是可以使用箭頭函數作爲 prop
下面這個例子中,子組件通過回調函數 onChange 實現了向父組件傳參
// 子組件
<script lang="ts">
// onChange 需要父組件提供
export let onChange = (v: number) => {};
let count: number = 0;
const addCount = () => {
count += 1;
typeof onChange === 'function' && onChange(count);
};
</script>
<button on:click={addCount}>Click</button>
<p>count: {count}</p>
// 父組件
<script lang="ts">
import Child from './child.svelte';
const onChange = (v: number) => {
console.log('onChange', v);
};
</script>
<Child {onChange} />
<!--
* 等價於:
* <Child onChange={onChange} />
-->
四、狀態管理:複雜情況的組件傳參
通過 props 可以很輕鬆的實現父組件對子組件的傳參
如果是兄弟組件之間傳參,可以運用狀態提升的思想來實現
但如果是更復雜的情況呢?比如祖孫組件,甚至是幾個沒有直接關係的組件。這時候就可以使用 Svelte 自帶的狀態管理
// stores/index.js
import { writable } from 'svelte/store';
export const titleStore = writable('Hello World');
export const userInfo = writable({
name: 'Wise.Wrong',
blog: 'https://www.cnblogs.com/wisewrong/',
});
svelte/store 模塊提供了三個函數 writable、readable、derived,分別用來創建可寫狀態、只讀狀態、派生狀態
其中最常用的是可寫狀態 writable, 上面的 stores/index.js 中就使用 writable 創建了兩個 store 對象
但 store 對象是不能直接用於頁面渲染的,比如下面的用法就會出錯
這是因爲 writable 創建的是包含 set、update、subscribe 方法的 store 對象
其中 subscribe 會在 store 更新的時候觸發,類似 Vue 中的 watch
基於這個特性,我們可以這樣讀取 store 的值:
它確實生效了,但這樣也太不優雅了,其實只需要在 store 前面加一個 $ 就行了
如果需要在組件中修改 store 的值,可以用到 set 和 update 方法
import { titleStore } from './stores';
const onChange = (v: string) => {
// set 接收的參數會作爲 store 的新值
titleStore.set(v);
};
const onUpdate = (str: string) => {
// update 可以接收一個函數,其返回值會作爲 store 的新值
titleStore.update((v: string) => v + str);
}
但如果是在表單中,有時候連 update 或 set 都不需要,因爲 store 可以配合 bind: 使用
<script lang="ts">
// parent.svelte
import { userInfo } from '../../stores';
import Child from './child.svelte';
</script>
<div class="title">This is <strong>{$userInfo?.name}</strong></div>
<Child />
<style>
.title {
margin-bottom: 12px;
}
</style>
<script lang="ts">
// child.svelte
import { userInfo } from '../../stores';
</script>
<section>
<div>
<span>姓名: </span>
<input type="text" bind:value={$userInfo.name}>
</div>
<div>
<span>博客: </span>
<input type="text" bind:value={$userInfo.blog}>
</div>
</section>