iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0
Modern Web

了不起的 Svelte系列 第 8

第 08 天:Svelte 中的 Javascript:宣告

  • 分享至 

  • xImage
  •  

第 08 天:Svelte 中的 Javascript:宣告

在許多夏日的夜晚,我鄰居的家中總是傳來陣陣宣告變數的聲音。在他藍藍的花園裡頭,男人女人像飛蛾一般,隨著耳語、美酒、星空、和 $ 翩翩起舞。

~節錄自《The Great Svelte:第三章》

第 08 天要講的事

  1. Svelte 當中的 Javascript:宣告

  我們已經明白 Svelte 能夠透過賦值 (assign, =) 這個動作,同步更新 Javascript 的變數以及 HTML 當中與這個變數相關的元素了。那麼再繼續問下去:Svelte 有辦法同樣根據賦值這個動作,同步去更新 Javascript 當中與這個變數相關的其他變數嗎?答案是肯定的。就讓我們來看看,Svelte 是用了什麼神奇的魔法來完成這個工作的吧!

Svelte 當中的 Javascript:宣告

  在一個前端專案當中,我們可能會用到不少 Javascript 變數來記錄專案的狀態。同時為了方便起見,可能也會有不少衍生 (或說參照,reference) 自變數的變數。舉例來說,我們可能會想要用一個變數代表陣列,接著另外再創造一個變數,用來代表陣列的長度。

let someState = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let otherState = someState.length;

  在互動式的使用者介面當中,當 someState 因為某些原因改變了,我們自然會希望衍生自 someState 的變數 otherState 也跟著更新,如此才能維持整個狀態的統一性。那麼 Svelte 如何幫助我們做到這件事呢?Svelte 提供了一個非常有趣的方式,也就是互動宣告 (reactive declaration),讓 Svelte 的編譯器知道何時該跟著更新衍生自變數的變數。
  互動宣告 (reactive declaration) 的作法很簡單,當我們宣告一個新的變數,這個新的變數是參照自其他變數時,只要在開頭加上 $: 就完成了:

let someState = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$: otherState = someState.length;

  otherState 是衍生自 someState 的變數,需要跟著 someState 的改變而更新。因此在宣告 otherState 的時候,我們在開頭加上 $:,Svelte 編譯器會創造出程式碼,幫忙追蹤 otherState 究竟是衍生自哪些變數,當那些變數改變時,便會跟著更新 otherState
  明白了做法,就讓我們實際嘗試一次看看吧。同樣來到 Counter.svelte 這個檔案,讓我們重新寫過 Javascript 的內容:

/src/lib/Counter.svelte
<script>
  let countArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  $: count = countArray.length;

  setInterval(() => {
    countArray = countArray.slice(1);
  }, 1000);
</script>

<section>
  <h1>Create Color Palette for Me!</h1>

  <div class='counter'>
    <button>
      <svg aria-hidden="true" viewBox="0 0 1 1">
        <path d="M0,0.5 L1,0.5" />
      </svg>
    </button>
    <div class="counter-viewer">
      <p>{count}</p>
    </div>
    <button>
      <svg aria-hidden="true" viewBox="0 0 1 1">
        <path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
      </svg>
    </button>
  </div>
</section>
  • 第二行:let countArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
      首先宣告一個變數 countArray

  • 第三行:$: count = countArray.length;
      接著利用 $: 宣告一個衍生自 countArray 的變數,也就是 count

  • 第六行:countArray = countArray.slice(1);
      每一秒鐘丟掉一個 countArray 陣列當中的元素。記得,在 Svelte 當中,為了讓編譯器知道變數更新這件事,必須要使用賦值 (assign, =)。所以這邊我們不是用原地 (in-place) 改變陣列的 countArray.shift(),而是 countArray = countArray.slice(1);

  • 第二十行:<p>{count}</p>
      將衍生自 countArray 的變數 count 顯示在 HTML 當中。

  這樣一來,就算完成互動宣告 (reactive declaration) 了,讓我們看一看成果吧。

https://i.ibb.co/xFKJbry/Vite-Svelte-Profile-1-Microsoft-Edge-2023-09-23-08-08-55.gif
圖一、10、9、8、7、6、5、4、3、2、1、0!

  要提醒的一點是,在做互動宣告時,並不需要把 let 擺在變數名稱前,即使是第一次宣告的變數也一樣。如果是第一次宣告的變數,Svelte 編譯器會在編譯階段自動幫我們補上需要的 let
為什麼會這樣呢?這其實是源自於 Javascript 本身的設計。
  不知道互動宣告 (reactive declaration) 的程式碼,對於第一次接觸 Svelte 的人來說,寫起來會不會很彆扭或是不習慣呢?不過 $: 可是完完全全符合 Javascript 規範的一種語法,叫做標籤陳述句 (labelled statement)。標籤陳述句的寫法是,先用一個標籤 (identifier) 加冒號 (:) 開頭,接著將需要的陳述句放在後面。只要呼叫這個標籤,就可以執行指定的陳述句。有興趣的讀者可以到 MDN Web Docs 來詳細查看標籤陳述句的說明 (連結)。
  而 Svelte 只是讓 $ 作為標籤陳述句的標籤,並藉由編譯器賦予這個特殊的標籤陳述句更多的功能,讓這個標籤陳述句可以追蹤陳述句內用到的所有變數,只要任何一個變數發生重新賦值得事件,就回過頭來跟著重新執行一次該陳述句的內容。這麼一來就能夠讓衍生的變數跟著所有參照的變數一起更新了。
  那麼現在是不是也不難理解為什麼在 $: 之後做的互動宣告 (reactive declaration) 不用 (實際上是根本不能) 加上 let 來宣告新的變數。因為加上 let 會使得重新執行這段程式碼時發生重複宣告變數的錯誤。
  那麼今天關於互動宣告 (reactive declaration) 的介紹就到這邊了,謝謝大家!


上一篇
第 07 天:Svelte 中的 Javascript:賦值
下一篇
第 09 天:Svelte 中的 Javascript:陳述
系列文
了不起的 Svelte30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言