Svelte 迷途求索(二) —— 組件傳參和狀態管理

一、簡單體驗

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>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章