跳至主要内容

就像你可以绑定到 DOM 元素一样,你也可以使用 bind:this 绑定到组件实例本身。

这在您需要以编程方式(而不是通过提供更新的 props)与组件交互的罕见情况下很有用。重新审视我们来自 几个练习前 的画布应用程序,最好添加一个按钮来清除屏幕。

首先,让我们从 Canvas.svelte 导出一个函数

Canvas
let canvas = $state();
let context = $state();
let coords = $state();

export function clear() {
	context.clearRect(0, 0, canvas.width, canvas.height);
}

然后,创建一个对组件实例的引用

App
let selected = $state(colors[0]);
let size = $state(10);
let showMenu = $state(true);

let canvas;
App
<Canvas bind:this={canvas} color={selected} size={size} />

最后,添加一个调用 clear 函数的按钮

App
<div class="controls">
	<button class="show-menu" onclick={() => showMenu = !showMenu}>
		{showMenu ? 'close' : 'menu'}
	</button>

	<button onclick={() => canvas.clear()}>
		clear
	</button>
</div>

在 GitHub 上编辑此页面

上一个 下一个
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<script>
	import Canvas from './Canvas.svelte';
	import { trapFocus } from './actions.svelte.js';
 
	const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet', 'white', 'black'];
 
	let selected = $state(colors[0]);
	let size = $state(10);
	let showMenu = $state(true);
</script>
 
<div class="container">
	<Canvas color={selected} size={size} />
 
	{#if showMenu}
		<div
			role="presentation"
			class="modal-background"
			onclick={(event) => {
				if (event.target === event.currentTarget) {
					showMenu = false;
				}
			}}
			onkeydown={(e) => {
				if (e.key === 'Escape') {
					showMenu = false;
				}
			}}
		>
			<div class="menu" use:trapFocus>
				<div class="colors">
					{#each colors as color}
						<button
							class="color"
							aria-label={color}
							aria-current={selected === color}
							style="--color: {color}"
							onclick={() => {
								selected = color;
							}}
						></button>
					{/each}
				</div>
 
				<label>
					small
					<input type="range" bind:value={size} min="1" max="50" />
					large
				</label>
			</div>
		</div>
	{/if}
 
	<div class="controls">
		<button class="show-menu" onclick={() => showMenu = !showMenu}>
			{showMenu ? 'close' : 'menu'}
		</button>
	</div>
</div>
 
<style>
	.container {
		position: fixed;
		left: 0;
		top: 0;
		width: 100%;
		height: 100%;
	}
 
	.controls {
		position: absolute;
		left: 0;
		top: 0;
		padding: 1em;
	}
 
	.show-menu {
		width: 5em;
	}
 
	.modal-background {
		position: fixed;
		display: flex;
		justify-content: center;
		align-items: center;
		left: 0;
		top: 0;
		width: 100%;
		height: 100%;
		backdrop-filter: blur(20px);
	}
 
	.menu {
		position: relative;
		background: var(--bg-2);
		width: calc(100% - 2em);
		max-width: 28em;
		padding: 1em 1em 0.5em 1em;
		border-radius: 1em;
		box-sizing: border-box;
		user-select: none;
	}
 
	.colors {
		display: grid;
		align-items: center;
		grid-template-columns: repeat(9, 1fr);
		grid-gap: 0.5em;
	}
 
	.color {
		aspect-ratio: 1;
		border-radius: 50%;
		background: var(--color, #fff);
		transform: none;
		filter: drop-shadow(2px 2px 3px rgba(0,0,0,0.2));
		transition: all 0.1s;
	}
 
	.color[aria-current="true"] {
		transform: translate(1px, 1px);
		filter: none;
		box-shadow: inset 3px 3px 4px rgba(0,0,0,0.2);
	}
 
	.menu label {
		display: flex;
		width: 100%;
		margin: 1em 0 0 0;
	}
 
	.menu input {
		flex: 1;
	}
</style>