除了屬性之外,元素還可以有指令,用於控制元素的行為。
on:eventname永久連結
on:eventname={handler}
on:eventname|modifiers={handler}
使用 on:
指令來偵聽 DOM 事件。
<script>
let count = 0;
/** @param {MouseEvent} event */
function handleClick(event) {
count += 1;
}
</script>
<button on:click={handleClick}>
count: {count}
</button>
<script lang="ts">
let count = 0;
function handleClick(event: MouseEvent) {
count += 1;
}
</script>
<button on:click={handleClick}>
count: {count}
</button>
處理常式可以內嵌宣告,且不影響效能。與屬性一樣,指令值可以加上引號,以利語法高亮顯示。
<button on:click={() => (count += 1)}>
count: {count}
</button>
使用 |
字元將修飾詞加入 DOM 事件。
<form on:submit|preventDefault={handleSubmit}>
<!-- the `submit` event's default is prevented,
so the page won't reload -->
</form>
可以使用下列修飾詞
preventDefault
— 在執行處理常式之前,呼叫event.preventDefault()
stopPropagation
— 呼叫event.stopPropagation()
,防止事件傳遞到下一個元素stopImmediatePropagation
- 呼叫event.stopImmediatePropagation()
,防止同一個事件的其他監聽器被觸發。passive
— 改善觸控/滾輪事件的捲動效能(Svelte 會在安全的情況下自動加入)nonpassive
— 明確設定passive: false
capture
— 在擷取階段觸發處理常式,而不是浮現階段once
— 在處理常式第一次執行後將其移除self
— 只有當event.target
是元素本身時才會觸發處理常式trusted
— 只有當event.isTrusted
為true
時才會觸發處理常式。也就是說,當事件是由使用者動作觸發時。
修飾詞可以串接在一起,例如 on:click|once|capture={...}
。
如果 on:
指令沒有值,組件將會轉送事件,表示組件的使用者可以偵聽該事件。
<button on:click> The component itself will emit the click event </button>
可以針對同一個事件有多個事件監聽器
<script>
let counter = 0;
function increment() {
counter = counter + 1;
}
/** @param {MouseEvent} event */
function track(event) {
trackEvent(event);
}
</script>
<button on:click={increment} on:click={track}>Click me!</button>
bind:property永久連結
bind:property={variable}
資料通常由上往下傳遞,從父層到子層。bind:
指令允許資料反向傳遞,從子層到父層。大多數繫結都特定於特定元素。
最簡單的繫結會反映屬性的值,例如 input.value
。
<input bind:value={name} />
<textarea bind:value={text} />
<input type="checkbox" bind:checked={yes} />
如果名稱與值相符,則可以使用簡寫。
<input bind:value />
<!-- equivalent to
<input bind:value={value} />
-->
數字輸入值會被強制轉換;即使 input.value
在 DOM 中只是一個字串,Svelte 仍會將其視為數字。如果輸入為空或無效(在 type="number"
的情況下),則值為 null
。
<input type="number" bind:value={num} />
<input type="range" bind:value={num} />
在具有 type="file"
的 <input>
元素上,可以使用 bind:files
取得 已選取檔案的 FileList
。它是唯讀的。
<label for="avatar">Upload a picture:</label>
<input accept="image/png, image/jpeg" bind:files id="avatar" name="avatar" type="file" />
如果您將 bind:
指令與 on:
指令一起使用,則它們在定義中的順序會影響在呼叫事件處理常式時繫結變數的值。
<script>
let value = 'Hello World';
</script>
<input
on:input={() => console.log('Old value:', value)}
bind:value
on:input={() => console.log('New value:', value)}
/>
在這裡,我們繫結到文字輸入的值,它使用 input
事件。其他元素上的繫結可能會使用不同的事件,例如 change
。
繫結 <select> 值永久連結
<select>
值繫結對應於所選 <option>
上的 value
屬性,它可以是任何值(不只是字串,這在 DOM 中通常是如此)。
<select bind:value={selected}>
<option value={a}>a</option>
<option value={b}>b</option>
<option value={c}>c</option>
</select>
<select multiple>
元素的行為類似於核取方塊群組。繫結變數是一個陣列,其中每個項目對應於每個所選 <option>
的 value
屬性。
<select multiple bind:value={fillings}>
<option value="Rice">Rice</option>
<option value="Beans">Beans</option>
<option value="Cheese">Cheese</option>
<option value="Guac (extra)">Guac (extra)</option>
</select>
當 <option>
的值與其文字內容相符時,可以省略屬性。
<select multiple bind:value={fillings}>
<option>Rice</option>
<option>Beans</option>
<option>Cheese</option>
<option>Guac (extra)</option>
</select>
具有 contenteditable
屬性的元素支援下列繫結
這些之間有細微的差異,請在此處 了解更多。
<div contenteditable="true" bind:innerHTML={html} />
<details>
元素支援繫結至 open
屬性。
<details bind:open={isOpen}>
<summary>Details</summary>
<p>Something small enough to escape casual notice.</p>
</details>
媒體元素繫結永久連結
媒體元素 (<audio>
和 <video>
) 有其自己的繫結集 — 七個唯讀繫結...
duration
(唯讀) — 影片的總長度,單位為秒buffered
(唯讀) —{start, end}
物件陣列played
(唯讀) — 同上seekable
(唯讀) — 同上seeking
(唯讀) — 布林值ended
(唯讀) — 布林值readyState
(唯讀) — 0 到 4(含)之間的數字
...以及五個雙向繫結
currentTime
— 影片目前的播放時間,單位為秒playbackRate
— 影片播放的速度,其中 1 為「正常」paused
— 這個應該不言而喻volume
— 0 到 1 之間的值muted
— 布林值,表示播放器是否靜音
影片另外有唯讀的 videoWidth
和 videoHeight
繫結。
<video
src={clip}
bind:duration
bind:buffered
bind:played
bind:seekable
bind:seeking
bind:ended
bind:readyState
bind:currentTime
bind:playbackRate
bind:paused
bind:volume
bind:muted
bind:videoWidth
bind:videoHeight
/>
圖片元素繫結永久連結
圖片元素 (<img>
) 有兩個唯讀繫結
naturalWidth
(唯讀) — 圖片的原始寬度,在圖片載入後可用naturalHeight
(唯讀) — 圖片的原始高度,在圖片載入後可用
<img
bind:naturalWidth
bind:naturalHeight
></img>
區塊層級元素繫結永久連結
區塊層級元素有 4 個唯讀繫結,使用類似 這個 的技術測量
clientWidth
clientHeight
offsetWidth
offsetHeight
<div bind:offsetWidth={width} bind:offsetHeight={height}>
<Chart {width} {height} />
</div>
bind:group永久連結
bind:group={variable}
可以一起運作的輸入可以使用 bind:group
。
<script>
let tortilla = 'Plain';
/** @type {Array<string>} */
let fillings = [];
</script>
<!-- grouped radio inputs are mutually exclusive -->
<input type="radio" bind:group={tortilla} value="Plain" />
<input type="radio" bind:group={tortilla} value="Whole wheat" />
<input type="radio" bind:group={tortilla} value="Spinach" />
<!-- grouped checkbox inputs populate an array -->
<input type="checkbox" bind:group={fillings} value="Rice" />
<input type="checkbox" bind:group={fillings} value="Beans" />
<input type="checkbox" bind:group={fillings} value="Cheese" />
<input type="checkbox" bind:group={fillings} value="Guac (extra)" />
bind:group
僅在輸入位於同一個 Svelte 元件中時運作。
bind:this永久連結
bind:this={dom_node}
若要取得 DOM 節點的參考,請使用 bind:this
。
<script>
import { onMount } from 'svelte';
/** @type {HTMLCanvasElement} */
let canvasElement;
onMount(() => {
const ctx = canvasElement.getContext('2d');
drawStuff(ctx);
});
</script>
<canvas bind:this={canvasElement} />
class:name永久連結
class:name={value}
class:name
class:
指令提供在元素上切換類別的較短方式。
<!-- These are equivalent -->
<div class={isActive ? 'active' : ''}>...</div>
<div class:active={isActive}>...</div>
<!-- Shorthand, for when name and value match -->
<div class:active>...</div>
<!-- Multiple class toggles can be included -->
<div class:active class:inactive={!active} class:isAdmin>...</div>
style:property永久連結
style:property={value}
style:property="value"
style:property
style:
指令提供在元素上設定多個樣式的簡寫。
<!-- These are equivalent -->
<div style:color="red">...</div>
<div style="color: red;">...</div>
<!-- Variables can be used -->
<div style:color={myColor}>...</div>
<!-- Shorthand, for when property and variable name match -->
<div style:color>...</div>
<!-- Multiple styles can be included -->
<div style:color style:width="12rem" style:background-color={darkMode ? 'black' : 'white'}>...</div>
<!-- Styles can be marked as important -->
<div style:color|important="red">...</div>
當 style:
指令與 style
屬性結合時,指令將優先。
<div style="color: blue;" style:color="red">This will be red</div>
use:action永久連結
use:action
use:action={parameters}
ts
action = (node :HTMLElement ,parameters : any) => {update ?: ( parameters : any) => void,destroy ?: () => void }
動作是在元素建立時呼叫的函式。它們可以傳回一個具有 destroy
方法的物件,該方法在元素卸載後呼叫
<script>
/** @type {import('svelte/action').Action} */
function foo(node) {
// the node has been mounted in the DOM
return {
destroy() {
// the node has been removed from the DOM
}
};
}
</script>
<div use:foo />
動作可以有一個參數。如果傳回的值具有 update
方法,則每當該參數變更時,它將在 Svelte 套用更新至標記後立即被呼叫。
別擔心我們為每個元件實例重新宣告
foo
函式的事實 — Svelte 會將任何不依賴於區域狀態的函式提升至元件定義之外。
<script>
export let bar;
/** @type {import('svelte/action').Action} */
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} />
在 svelte/action
頁面中閱讀更多資訊。
transition:fn永久連結
transition:fn
transition:fn={params}
transition:fn|global
transition:fn|global={params}
transition:fn|local
transition:fn|local={params}
ts
transition = (node :HTMLElement ,params : any,options : {direction : 'in' | 'out' | 'both' }) => {delay ?: number ,duration ?: number ,easing ?: ( t : number) =>number ,css ?: ( t : number,u : number) =>string ,tick ?: ( t : number,u : number) => void}
轉場是由於狀態變更而觸發元素進入或離開 DOM。
當一個區塊正在轉換時,區塊內的元素,包括那些沒有自己轉換的元素,都會保留在 DOM 中,直到區塊中的每個轉換都已完成。
transition:
指令表示雙向轉換,這表示在轉換進行中時可以順利反轉。
{#if visible}
<div transition:fade>fades in and out</div>
{/if}
轉換預設為區域性的(在 Svelte 3 中,它們預設為全域性的)。區域轉換只會在它們所屬的區塊建立或銷毀時播放,不會在父區塊建立或銷毀時播放。
{#if x}
{#if y}
<!-- Svelte 3: <p transition:fade|local> -->
<p transition:fade>fades in and out only when y changes</p>
<!-- Svelte 3: <p transition:fade> -->
<p transition:fade|global>fades in and out when x or y change</p>
{/if}
{/if}
預設情況下,intro 轉換不會在第一次渲染時播放。您可以透過在建立元件時設定
intro: true
,並將轉換標記為global
來修改此行為。
轉換參數永久連結
與動作一樣,轉換可以有參數。
(雙重 {{大括號}}
不是特殊語法;這是一個表達式標籤內的物件文字。)
{#if visible}
<div transition:fade={{ duration: 2000 }}>fades in and out over two seconds</div>
{/if}
自訂轉換函式永久連結
轉換可以使用自訂函式。如果回傳的物件有 css
函式,Svelte 將建立一個在元素上播放的 CSS 動畫。
傳遞給 css
的 t
參數是在套用 easing
函式後介於 0
和 1
之間的值。進入轉換從 0
到 1
執行,離開轉換從 1
到 0
執行 — 換句話說,1
是元素的自然狀態,就像沒有套用任何轉換一樣。u
參數等於 1 - t
。
在轉換開始之前,會重複呼叫函式,並使用不同的 t
和 u
參數。
<script>
import { elasticOut } from 'svelte/easing';
/** @type {boolean} */
export let visible;
/**
* @param {HTMLElement} node
* @param {{ delay?: number, duration?: number, easing?: (t: number) => number }} params
*/
function whoosh(node, params) {
const existingTransform = getComputedStyle(node).transform.replace('none', '');
return {
delay: params.delay || 0,
duration: params.duration || 400,
easing: params.easing || elasticOut,
css: (t, u) => `transform: ${existingTransform} scale(${t})`
};
}
</script>
{#if visible}
<div in:whoosh>whooshes in</div>
{/if}
自訂轉換函式也可以回傳一個 tick
函式,該函式會在轉換期間使用相同的 t
和 u
參數呼叫。
如果可以的話,使用
css
取代tick
,CSS 動畫可以在主執行緒之外執行,避免在較慢的裝置上出現卡頓。
<script>
export let visible = false;
/**
* @param {HTMLElement} node
* @param {{ speed?: number }} params
*/
function typewriter(node, { speed = 1 }) {
const valid = node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE;
if (!valid) {
throw new Error(`This transition only works on elements with a single text node child`);
}
const text = node.textContent;
const duration = text.length / (speed * 0.01);
return {
duration,
tick: (t) => {
const i = ~~(text.length * t);
node.textContent = text.slice(0, i);
}
};
}
</script>
{#if visible}
<p in:typewriter={{ speed: 1 }}>The quick brown fox jumps over the lazy dog</p>
{/if}
<script lang="ts">
export let visible = false;
function typewriter(node: HTMLElement, { speed = 1 }: { speed?: number }) {
const valid = node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE;
if (!valid) {
throw new Error(`This transition only works on elements with a single text node child`);
}
const text = node.textContent;
const duration = text.length / (speed * 0.01);
return {
duration,
tick: (t) => {
const i = ~~(text.length * t);
node.textContent = text.slice(0, i);
},
};
}
</script>
{#if visible}
<p in:typewriter={{ speed: 1 }}>The quick brown fox jumps over the lazy dog</p>
{/if}
如果轉場傳回函式而不是轉場物件,該函式會在下一微任務中呼叫。這允許多個轉場協調,讓 交叉淡出效果 成為可能。
轉場函式也會接收第三個參數 options
,其中包含轉場的資訊。
options
物件中可用的值為
direction
- 根據轉場類型,為in
、out
或both
之一
轉場事件permalink
具有轉場的元素除了任何標準 DOM 事件外,還會發送下列事件
introstart
introend
outrostart
outroend
{#if visible}
<p
transition:fly={{ y: 200, duration: 2000 }}
on:introstart={() => (status = 'intro started')}
on:outrostart={() => (status = 'outro started')}
on:introend={() => (status = 'intro ended')}
on:outroend={() => (status = 'outro ended')}
>
Flies in and out
</p>
{/if}
in:fn/out:fnpermalink
in:fn
in:fn={params}
in:fn|global
in:fn|global={params}
in:fn|local
in:fn|local={params}
out:fn
out:fn={params}
out:fn|global
out:fn|global={params}
out:fn|local
out:fn|local={params}
類似於 transition:
,但僅適用於進入 (in:
) 或離開 (out:
) DOM 的元素。
與 transition:
不同,使用 in:
和 out:
套用的轉場不是雙向的,如果在轉場進行中區塊被 outro,in 轉場將繼續與 out 轉場「播放」,而不是反轉。如果中斷 out 轉場,轉場將從頭開始重新啟動。
{#if visible}
<div in:fly out:fade>flies in, fades out</div>
{/if}
animate:fnpermalink
animate:name
animate:name={params}
ts
animation = (node :HTMLElement , {from :DOMRect ,to :DOMRect } ,params : any) => {delay ?: number ,duration ?: number ,easing ?: ( t : number) =>number ,css ?: ( t : number,u : number) =>string ,tick ?: ( t : number,u : number) => void}
ts
DOMRect {bottom:number ,height :number ,left :number ,right :number ,top :number ,width :number ,x :number ,y :number }
當keyed each 區塊的內容重新排序時,會觸發動畫。當元素新增或移除時,動畫不會執行,只有當 each 區塊中現有資料項目的索引變更時,才會執行。Animate 指令必須位於 keyed each 區塊的直接子元素上。
<!-- When `list` is reordered the animation will run-->
{#each list as item, index (item)}
<li animate:flip>{item}</li>
{/each}
動畫參數永久連結
與動作和轉場一樣,動畫也可以有參數。
(雙重 {{大括號}}
不是特殊語法;這是一個表達式標籤內的物件文字。)
{#each list as item, index (item)}
<li animate:flip={{ delay: 500 }}>{item}</li>
{/each}
自訂動畫函式永久連結
動畫可以使用提供node
、animation
物件和任何參數
作為引數的自訂函式。animation
參數是一個包含from
和to
屬性的物件,每個屬性都包含一個DOMRect,描述元素在其開始
和結束
位置的幾何形狀。from
屬性是在其開始位置的元素的 DOMRect,而to
屬性是在清單重新排序且 DOM 更新後,元素在其最終位置的 DOMRect。
如果傳回的物件有css
方法,Svelte 將會建立一個在元素上播放的 CSS 動畫。
傳遞給css
的t
引數是一個在應用easing
函式後從0
到1
的值。u
引數等於1 - t
。
此函式會在動畫開始之前重複呼叫,並使用不同的t
和u
引數。
<script>
import { cubicOut } from 'svelte/easing';
/**
* @param {HTMLElement} node
* @param {{ from: DOMRect; to: DOMRect }} states
* @param {any} params
*/
function whizz(node, { from, to }, params) {
const dx = from.left - to.left;
const dy = from.top - to.top;
const d = Math.sqrt(dx * dx + dy * dy);
return {
delay: 0,
duration: Math.sqrt(d) * 120,
easing: cubicOut,
css: (t, u) => `transform: translate(${u * dx}px, ${u * dy}px) rotate(${t * 360}deg);`
};
}
</script>
{#each list as item, index (item)}
<div animate:whizz>{item}</div>
{/each}
自訂動畫函數也可以傳回一個 tick
函數,它會在動畫 期間 以相同的 t
和 u
參數呼叫。
如果可以的話,使用
css
取代tick
,CSS 動畫可以在主執行緒之外執行,避免在較慢的裝置上出現卡頓。
<script>
import { cubicOut } from 'svelte/easing';
/**
* @param {HTMLElement} node
* @param {{ from: DOMRect; to: DOMRect }} states
* @param {any} params
*/
function whizz(node, { from, to }, params) {
const dx = from.left - to.left;
const dy = from.top - to.top;
const d = Math.sqrt(dx * dx + dy * dy);
return {
delay: 0,
duration: Math.sqrt(d) * 120,
easing: cubicOut,
tick: (t, u) => Object.assign(node.style, { color: t > 0.5 ? 'Pink' : 'Blue' })
};
}
</script>
{#each list as item, index (item)}
<div animate:whizz>{item}</div>
{/each}