transition:
transition は、state の変化の結果として DOM に要素が出入りする際にトリガーされます。
ブロック (例えば {#if ...}
ブロック) が外へ transition している間、その中のすべての要素 (独自の transition を持たないものも含む) は、ブロック内のすべての transition が完了するまで DOM に保持されます。
transition:
ディレクティブは 双方向 transition を示します。これにより、transition の進行中でもスムーズに反転させることができることを意味しています。
<script>
import { fade } from 'svelte/transition';
let visible = $state(false);
</script>
<button onclick={() => visible = !visible}>toggle</button>
{#if visible}
<div transition:fade>fades in and out</div>
{/if}
Built-in transitions
組み込みの transition は、svelte/transition
モジュールからインポートすることができます。
Local vs global
transition はデフォルトで local です。local transition は、それが属するブロックが作成または破棄されるときにのみ実行され、親ブロックが作成または破棄されるときには実行されません。
{#if x}
{#if y}
<p transition:fade>fades in and out only when y changes</p>
<p transition:fade|global>fades in and out when x or y change</p>
{/if}
{/if}
Transition parameters
transition にはパラメータを指定することができます。
(二重の {{中括弧}}
は特別な構文ではありません。これは式タグ内のオブジェクトリテラルです。)
{#if visible}
<div transition:fade={{ duration: 2000 }}>fades in and out over two seconds</div>
{/if}
Custom transition functions
transition = (node: HTMLElement
node: HTMLElement, params: any
params: any, options: {
direction: "in" | "out" | "both";
}
options: { direction: "in" | "out" | "both"
direction: 'in' | 'out' | 'both' }) => {
delay?: number,
duration?: number,
easing?: (t: number
t: number) => number,
css?: (t: number
t: number, u: number
u: number) => string,
tick?: (t: number
t: number, u: number
u: number) => void
}
transition にはカスタム関数を使用することができます。返されるオブジェクトに css
関数が含まれている場合、Svelte は web animation のキーフレームを生成します。
css
に渡される t
引数は、easing
関数が適用された後の 0
から 1
の間の値です。in transition は 0
から 1
に進行し、out transition は 1
から 0
に進行します — 言い換えると、1
は transition が適用されていない要素の自然な状態です。u
引数は 1 - t
に等しい値です。
この関数は、transition が開始される前に、異なる 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}
<script lang="ts">
import { elasticOut } from 'svelte/easing';
export let visible: boolean;
function whoosh(node: HTMLElement, params: { delay?: number, duration?: number, easing?: (t: number) => number }) {
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}
カスタムの transition 関数は、transition の途中で同じ t
と u
の引数と共に呼び出される tick
関数を返すこともできます。
tick
の代わりにcss
を使用できる場合は、そうしてください — web animation はメインスレッドの外で実行されるため、低速なデバイスでのカクつきを防ぐことができます。
<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}
transition が transition オブジェクトの代わりに関数を返す場合、その関数は次のマイクロタスク内で呼び出されます。これにより、複数の transition が調整され、クロスフェード効果 を実現できます。
transition 関数は、transition に関する情報を含む第3引数 options
を受け取ります。
options
オブジェクトで使用可能な値は以下の通りです:
direction
- transition のタイプに応じてin
、out
、both
のいずれか
Transition events
transition を持つ要素は、標準の DOM イベントに加えて次のイベントをディスパッチします:
introstart
introend
outrostart
outroend
{#if visible}
<p
transition:fly={{ y: 200, duration: 2000 }}
onintrostart={() => (status = 'intro started')}
onoutrostart={() => (status = 'outro started')}
onintroend={() => (status = 'intro ended')}
onoutroend={() => (status = 'outro ended')}
>
Flies in and out
</p>
{/if}