這是〈Svelte 從小白到入門〉系列的第三集,各集連結如下:
- 〈Svelte 從小白到入門(一)元件、事件、Reactivity〉
- 〈Svelte 從小白到入門(二)Props、邏輯、迴圈、Await〉
- 〈Svelte 從小白到入門(三)事件〉
- 〈Svelte 從小白到入門(四)數據綁定〉
- 〈Svelte 從小白到入門(五)生命週期〉
- 〈Svelte 從小白到入門(六)Store〉
- 〈Svelte 從小白到入門(七)動態效果〉
- 〈Svelte 從小白到入門(八)進出場效果〉
- 〈Svelte 從小白到入門(九)動畫效果〉
- 〈Svelte 從小白到入門(十)Action〉
- 〈Svelte 從小白到入門(十一)CSS Class〉
- 〈Svelte 從小白到入門(十二)Slot〉
- 〈Svelte 從小白到入門(十三)Context〉
- 〈Svelte 從小白到入門(十四)Svelte 的特殊元素〉
- 〈Svelte 從小白到入門(十五)Module Context〉
- 〈Svelte 從小白到入門(十六)Debugging〉
- 〈Svelte 從小白到入門(十七)結束與展望〉
在第一集我們談到 reactivity 時也簡短的用到了 Svelte 的事件綁定 on:click
的語法,這集我們要探索更多 Svelte 的事件機制。
事件
能ㄤㄤㄤ的不只小叮噹,Svelte 也可以ㄤㄤㄤ。
下面是 on:mousemove
的示例,在紅色的 <div>
,我們呼叫 handleMousemove()
給出滑鼠座標,相當直白(直白是種高尚的情操),而在橘色的 <div>
,我們也可以改用在 HTML 用 inline 的方式呼叫一般函式或匿名函式:
事件修飾器
事件也有裝飾器,Svelte 原文稱為 modifier,而不是 decorator,不論名字為何,他們的角色是相同的—改變對象原有的行為。
下面這個例子用上了 once
裝飾器,所以點擊的行為只會觸發一次事件函式:
注意裝飾器的語法 on:click|once
中間有個管道符號 |
連接事件與修飾器。
至此我們已經看過 Svelte 兩種風格的修飾器語法:
@html string
,@html
讓字串不做跳脫處理,而@html
這種有@
符號的語法看起來像是 Python 風格的裝飾器語法。on:click|once
,once
讓點擊事件只發生一次,而|once
這種有|
管線符號的語法看起來像是 Unix 系的管道語法
同時摻用兩種風格的語法,讓 Svelte 看起來是混亂的,如果把 @html string
改以 string|html
,感覺起來整體風格會更為一致。
不過木已成舟,讓我們繼續跟著遊戲規則玩下去。
既有的事件修飾器如下,很偷懶的剪下貼上原文不解釋:
preventDefault
- callsevent.preventDefault()
before running the handler. Useful for client-side form handling, for example.stopPropagation
- callsevent.stopPropagation()
, preventing the event reaching the next element.passive
- improves scrolling performance on touch / wheel events (Svelte will add it automatically where it’s safe to do so).nonpassive
- explicitly setpassive: false
.capture
- fires the handler during the capture phase instead of the bubbling phase (MDN docs)once
- remove the handler after the first time it runs.self
- only trigger handler if event.target is the element itself.trusted
- only trigger handler ifevent.isTrusted
istrue
. I.e. if the event is triggered by a user action.
事件修飾器也可以像 Unix 管道一樣,串在一起:on:click|once|capture={...}
。
事件分派(Dispatch)與轉發(Forwarding)
Svelte 元件之間可以分派事件,在下面的示例裡,按鈕發生的事情如下:
- 按下 Inner 元件的按鈕
- 點擊觸發 Inner 按鈕的
on:click={sayHello}
sayHello()
內的dispatch('message')
又觸發父元件 App 的message
事件message
事件又觸發handleMessage()
handleMessage()
內執行了alert()
跳出提示框
這整個分派的機制得以實現,是靠 Svelte 提供的 createEventDispatcher()
,我們用它創建一個 dispatch
實體,供派送事件之用。
注意到父元件 App 內的這行:
<Inner on:message="{handleMessage}"/>
這邊是調用了 Inner 元件,不過 message
事件是發生在在 App 元件上的,這是 on:
事件綁定的語法,並非 props 的語法,雖然兩者長的有那麼一點像…。
基於以上的概念,我們讓它複雜一點,在 App 和 Inner 中間夾一層 Outer 元件,用 App 包 Outer、Outer 包 Inner 的方式形成巢狀引用,因為 Svelte 的事件沒有「冒泡」的機制,所以前一個例子的 Inner 丟出的 message
事件被 Outer 收到就停了,並不會自然而然的再往外丟給 App,因此在不改程式碼的情況下,按鈕自然也不會有反應的。
想讓事件往外轉發,得利用 Svelte 的轉發機制(語法糖),在 Outer 元件內,調用 Inner 之處,加上 on:message
的綁定語法,Svelte 就知道「哦,要轉發出去」,看起來很簡單,但個人認為頗不自然…:
事件轉發的機制也可以套用在原生的 DOM 物件上,按鈕加個 on:click
就會把點擊事件往外轉發出去了:
小結
整理本集重點:
- 事件以
on:
語法綁定 - 可以在 Svelte 的 HTML 元素內寫 inline 的函式
- 事件可以搭配管道符號
|
接上修飾器,並且可以串接多個修飾器 - Svelte 提供了用
createEventDispatcher()
建立的實例做事件分派的機制 - Svelte 的事件不會冒泡,要轉送事件得用像
on:click
這樣的語句向外轉送點擊事件
原本一集可以寫好幾個主題,現在一集只能寫一個主題,究竟會不會斷尾呢?讓我們看下去…。
(待續)