Context APIは、プロパティとしてデータや関数を渡したり、多数のイベントをディスパッチしたりすることなく、コンポーネント同士が「会話」するためのメカニズムを提供します。これは高度な機能ですが、便利な機能です。この演習では、ジェネラティブアートの先駆者の1人であるジョージ・ニースのSchotterをContext APIを使って再現します。
Canvas.svelte
内には、キャンバスにアイテムを追加するaddItem
関数があります。<Canvas>
内の<Square>
のようなコンポーネントで、setContext
を使用して利用できるようにすることができます。
キャンバス
import { setContext } from 'svelte';
import { SvelteSet } from 'svelte/reactivity';
let { width = 100, height = 100, children } = $props();
let canvas;
let items = new SvelteSet();
setContext('canvas', { addItem });
function addItem(fn) {
$effect(() => {
items.add(fn);
return () => items.delete(fn);
});
}
子コンポーネント内では、getContext
を使用してコンテキストを取得できます。
四角形
import { getContext } from 'svelte';
let { x, y, size, rotate } = $props();
getContext('canvas').addItem(draw);
今のところ、つまらないですね。グリッドに少しランダム性を追加しましょう。
アプリ
<div class="container">
<Canvas width={800} height={1200}>
{#each Array(12) as _, c}
{#each Array(22) as _, r}
<Square
x={180 + c * 40 + jitter(r * 2)}
y={180 + r * 40 + jitter(r * 2)}
size={40}
rotate={jitter(r * 0.05)}
/>
{/each}
{/each}
</Canvas>
</div>
setContext
とgetContext
は、コンテキストが正しくバインドされるように、コンポーネントの初期化中に呼び出す必要があります。この場合のキーである'canvas'
は、文字列でなくても構いません。これは、コンテキストにアクセスできるユーザーを制御するのに便利です。
コンテキストオブジェクトには、リアクティブな状態を含め、任意のものを入れることができます。これにより、時間の経過とともに変化する値を子コンポーネントに渡すことができます。
// in a parent component import { setContext } from 'svelte'; let context = $state({...}); setContext('my-context', context);
// in a child component import { getContext } from 'svelte'; const context = getContext('my-context');
前へ 次へ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<script>
import Canvas from './Canvas.svelte';
import Square from './Square.svelte';
// we use a seeded random number generator to get consistent jitter
let seed = 1;
function random() {
seed *= 16807;
seed %= 2147483647;
return (seed - 1) / 2147483646;
}
function jitter(amount) {
return amount * (random() - 0.5);
}
</script>
<div class="container">
<Canvas width={800} height={1200}>
{#each Array(12) as _, c}
{#each Array(22) as _, r}
<Square
x={180 + c * 40}
y={180 + r * 40}
size={40}
/>
{/each}
{/each}
</Canvas>
</div>
<style>
.container {
height: 100%;
aspect-ratio: 2 / 3;
margin: 0 auto;
background: rgb(224, 219, 213);
filter: drop-shadow(0.5em 0.5em 1em rgba(0, 0, 0, 0.1));
}
</style>