Svelte 使用 Actions
tags: Svelte
category: Front-End
description: Svelte 使用 Actions
created_at: 2023/04/18 12:00:00
前言
這個我覺得比較像 Vue 3
的指令(directive
),都是綁在 DOM
上面,然後可以根據生命週期去做事。
然後剛剛回去看發現我的 Vue 3 好像沒寫到指令
總之這篇就會以我之前練比賽的時候做的指令當範例,轉換成 Svelte
的版本。
是一個子功能,當初把他抽出來當指令,因為覺得程式碼會變得更漂亮
基本用法
語法是 use:xxx
,然後那個 xxx
是一個函數,先看看函數定義:
action = (node: HTMLElement, parameters: any) => {
update?: (parameters: any) => void,
destroy?: () => void
}
然後官方也有提供淺顯易懂的範例:
<script>
export let bar;
function foo(node, bar) {
// the node has been mounted in the DOM
return {
update(bar) {
// the value of `bar` has changed
},
destroy() {
// the node has been removed from the DOM
}
};
}
</script>
<div use:foo={bar}></div>
簡單來說就是 node
會吃到你綁定的元素,而 parameters
則是上例的 bar
,然後這個函數會在 mounted
被觸發,也可以回傳兩個函數:
update
: 當parameters
有變更的時候destroy
: 當node
被destroy
的時候觸發
再來看基礎範例:
<script lang="ts">
function hello(node: HTMLElement) {
console.log(node);
}
</script>
<div use:hello>Hello World</div>
這樣就會在 console
看到那個 div
被印出來,再來你就可以做一堆處理了。
例如你也可以為他監聽事件:
function hello(node: HTMLElement) {
node.addEventListener('click', () => {
console.log('click');
});
}
也可以把事件綁在 document
身上,不過如果綁在 node
以外,要記得一定要回傳 destroy
的時候做一些清理(例如刪除事件)。
如果綁在 node
上的話也可以養成好習慣做清理,如果你想照顧比較舊的瀏覽器的話,因為他可能沒有處理好而一樣導致memory leak
範例
因為我一時想不到其他簡單的Demo
範例,所以直接來看實際案例吧
需求是這樣子的,我希望透過 use:touch
,可以讓元素在電腦版可以像手機上一樣透過點擊然後動滑鼠來做捲動。
所以首先先來做一塊區域:
<div style="width: 200px; height: 200px; overflow: scroll;">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
<li>12</li>
<li>13</li>
<li>14</li>
<li>15</li>
<li>16</li>
<li>17</li>
<li>18</li>
<li>19</li>
<li>20</li>
</ul>
</div>
然後宣告 touch
的 action
出來用:
function touch(node: HTMLElement) {
node.dataset.touch = 'false';
const mousedown = () => {
node.dataset.touch = 'true';
};
const mousemove = (e: MouseEvent) => {
if (node.dataset.touch === 'true') {
node.scrollTop -= e.movementY;
node.scrollLeft -= e.movementX;
}
};
const mouseup = () => {
node.dataset.touch = 'false';
};
node.addEventListener('mousedown', mousedown);
node.addEventListener('mousemove', mousemove);
window.addEventListener('mouseup', mouseup);
return {
destroy() {
node.removeEventListener('mousedown', mousedown);
node.removeEventListener('mousemove', mousemove);
window.removeEventListener('mouseup', mouseup);
}
};
}
最後記得套用到 div
身上:
<div style="width: 200px; height: 200px; overflow: scroll;" use:touch>
<!-- 略... -->
</div>
這時就可以透過滑鼠點擊然後上下滑動來捲動了。
有參數的範例
這邊臨時想到的範例是之前寫測試的時候會用到 test-id
這個屬性,但又不希望 production
出去的時候暴露出來讓爬蟲太好抓(雖然好像也有現成的套件可以幫忙拿掉),所以做了一個指令,只在 development
或 testing
狀態(總之就是非 production
)的時候才產生 test-id
來用。
這個需求反而比上面的還單純:
function testid(node: HTMLElement, testid: string) {
if (import.meta.env.MODE !== 'production') {
node.setAttribute('data-testid', testid);
}
}
然後用起來也很簡單:
<div use:testid={'hi'}>Hi</div>
然後就可以自己執行跟 Build
看看,甚至可以寫測試看看,都會是正常的。
總結
這個功能相對簡單很多,但是也很有彈性可以做更多事情,總之 use:xxx
就是會去吃 xxx
這個函數,然後會得到 node
跟後面傳入的 params
,這也非常的直覺。