Skip to main content
基本 Svelte
介绍
反应性
属性
逻辑
事件
绑定
类和样式
动作
转换
高级 Svelte
高级反应性
重用内容
运动
高级绑定
高级转换
上下文 API
特殊元素
<script module>
后续步骤
基本 SvelteKit
介绍
路由
加载数据
标题和 cookie
共享模块
表单
API 路由
$app/state
错误和重定向
高级 SvelteKit
钩子
页面选项
链接选项
高级路由
高级加载
环境变量
结论

上下文 API 为组件提供了一种机制,使它们可以相互 ‘talk’,而无需传递数据和函数作为 props,或分派大量事件。这是一个高级功能,但很有用。在这个练习中,我们将使用上下文 API 重新创建 George Nees(生成艺术的先驱之一)的 Schotter

¥The context API provides a mechanism for components to ‘talk’ to each other without passing around data and functions as props, or dispatching lots of events. It’s an advanced feature, but a useful one. In this exercise, we’re going to recreate Schotter by George Nees — one of the pioneers of generative art — using the context API.

Canvas.svelte 内部,有一个 addItem 函数可以将一个项目添加到画布。我们可以使用 setContext 将其提供给 <Canvas> 内部的组件,例如 <Square>

¥Inside Canvas.svelte, there’s an addItem function that adds an item to the canvas. We can make it available to components inside <Canvas>, like <Square>, with setContext:

Canvas
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 获取上下文:

¥Inside child components, we can now get the context with, well, getContext:

Square
import { getContext } from 'svelte';

let { x, y, size, rotate } = $props();

getContext('canvas').addItem(draw);

到目前为止,所以...无聊。让我们为网格添加一些随机性:

¥So far, so... boring. Let’s add some randomness to the grid:

App
<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>

必须在组件初始化期间调用 setContextgetContext,以便正确绑定上下文。键 — 在本例中为 'canvas' — 可以是任何你喜欢的内容,包括非字符串,这对于控制谁可以访问上下文很有用。

¥setContext and getContext must be called during component initialisation, so that the context can be correctly bound. The key — 'canvas' in this case — can be anything you like, including non-strings, which is useful for controlling who can access the context.

你的上下文对象可以包含任何内容,包括反应状态。这允许你将随时间变化的值传递给子组件:

¥[!NOTE] Your context object can include anything, including reactive state. This allows you to pass values that change over time to child components:

// 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>