就像您可以綁定到 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>
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>