在七月的一個早晨九點鐘,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 的事件處理的介紹就到這邊了,謝謝大家。