在七月的一個早晨九點鐘,Svelte 氣派的轎車顛顛頗簸的開上我家門口那條滿布碎石的車道,從三音階的喇叭裡爆出了一陣 HTML 的事件 (event)。
~節錄自《The Great Svelte:第四章》
系列文進行到這邊,我們已經對 Svelte 的運作邏輯了解了不少,知道該如何做出隨著狀態 (state) 改變而更新 Javascript 變數以及 HTML 元素的互動專案了。今天就要來開始討論互動的另一個主角,也就是使用者介面 (user interface)。看看如何在使用者介面當中觸發事件,藉此改變應用程式的狀態 (state)。
  對 HTML 網頁製作不陌生的讀者們,應該知道若要在使用者介面當中觸發各種事件,作法就是在欲觸發事件的 HTML 元素上,利用 addEventListener 做出事件處理器 (event handler)。因此通常會在 Javascript 當中看到兩行程式碼:
const eventTarget = document.querySelector('someSelector');
eventTarget.addEventListener(eventHandler);
第一行先用 CSS 選擇器將需要的 HTML 元素找出來,接著在該元素加上事件處理器。那麼在 Svelte 當中又該怎麼做呢?既然 Svelte 允許我們直接在 HTML 當中展開屬於 Javascript 的領域,直接撰寫 Javascript,那麼 Svelte 當中的事件處裡應該可以更輕鬆地完成囉:
<div on:event={eventHandler}/>
<div on:event={eventHandler}/><div>),使用關鍵字 on:,後面加上事件名稱,如 click、mousemove、keydown 等等,表示想要聆聽該事件。接著就像在寫 HTML 元素的屬性那樣,以 ={eventHandler} 展開 Javascript 的領域,並放入我們定義的事件處理器 eventHandler。  這就是在 Svelte 當中事件處理的寫法。是不是相當簡單呢?那就讓我們在專案當中實際來試一試。我們沿用昨天 App.svelte 當中的程式碼不多做修改:
/src/App.svelte
<!-- 在 Javascript 當中 import Counter -->
<script>
  import Counter from './lib/Counter.svelte';
  let someState = 'TheGreatSvelte';
  const sparkle = (text) => {
    const sparkles = ['★', '☆', '✧', '✪'];
    const randomSparkles = () => sparkles[Math.floor(Math.random() * sparkles.length)];
    const sparkledText = text.split('').reduce((a, c) => a + randomSparkles() + c, '');
    return sparkledText;
  }
  const href = 'https://ithelp.ithome.com.tw/users/20120178/ironman/7031';
</script>
<main>
  <!-- 在 HTML 當中直接嵌入 Counter -->
  <Counter />
  <p class='comment'>Check out <a {href}>Svelte Tutorial</a>, the awesome article powered by {sparkle(someState)}!</p>
</main>
第三行:import Counter from './lib/Counter.svelte';
  引入 Counter。
第十八行:<Counter />
  放入 <Counter />。
  接著開始來修改 Counter.svelte,讓我們看了好久的 <button> 來做點事情:
/src/lib/Counter.svelte
<script>
  export let count = 100;
  const handleMinus = () => count -= 1;
  const handlePlus = () => count += 1;
</script>
<section>
  <h1>Create Color Palette for Me!</h1>
  <div class='counter'>
    <button on:click={handleMinus}>
      <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 on:click={handlePlus}>
      <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>
第二行:export let count = 100;
  宣告一個變數 count,這個變數同時也是 Counter 的 Property。
第四行:const handleMinus = () => count -= 1;
  宣告一個函式 handleMinus。該函式的作用是讓 count 這個變數的值減 1。
第五行:const handlePlus = () => count += 1;
  宣告一個函式 handlePlus。該函式的作用是讓 count 這個變數的值加 1。
第十二行:<button on:click={handleMinus}>
  在這個 <button> 加上作為事件處理器的函式 handleMinus,只要該 <button> 被按下,就會呼叫這個函式。
第十八行:<p>{count}</p> 
  將 count 的值顯示於 <p> 當中。
第二十行:<button on:click={handlePlus}>
  在這個 <button> 加上作為事件處理器的函式 handlePlus,只要該 <button> 被按下,就會呼叫這個函式。

圖一、加加減減減減加加
  這麼一來就完成了,是不是可以透過兩個 <button> 隨心所欲的改變 count 了呢!
既然 Svelte 允許我們在 HTML 當中展開 Javascript 的領域直接撰寫 Javascript,對於今天這個相當簡單的減減加加函式,是不是不需要另外在 Javascript 當中將函式定義出來,而可以直接在 HTML 當中寫下行內 (inline) 事件處理器呢?沒錯,您真內行,答案是肯定的:
/src/lib/Counter.svelte
<script>
  export let count = 100;
</script>
<section>
  <h1>Create Color Palette for Me!</h1>
  <div class='counter'>
    <button on:click={() => count -= 1}>
      <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 on:click={() => count += 1}>
      <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>
第九行:<button on:click={() => count -= 1}>
  我們把原本定義在 Javascript 的 handleMinus 給刪掉,直接在 <button> 撰寫我們需要的事件處理器函式。因為函式內容相當簡單,所以看起來也很乾淨整齊。
第十七行:<button on:click={() => count += 1}>
  同樣的,我們把原本定義在 Javascript 的 handlePlus 給刪掉,直接在 <button> 撰寫我們需要的事件處理器函式。

圖二、運作如常的行內 (inline) 處理器
那麼今天關於 Svelte 的事件處理的介紹就到這邊了,謝謝大家。