Kurs Svelte i SvelteKit · Moduł 4: Props i zdarzenia
Dwukierunkowe wiązania ($bindable)
W tej lekcji4
Czasem potrzebujesz, by dziecko mogło modyfikować dane rodzica. Użyj $bindable!
$bindable w Svelte 5
<!-- SearchInput.svelte -->
<script>
let { value = $bindable('') } = $props();
</script>
<input bind:value placeholder="Szukaj wojownika..." /><!-- Parent.svelte -->
<script>
import SearchInput from './SearchInput.svelte';
let searchQuery = $state('');
</script>
<SearchInput bind:value={searchQuery} />
<p>Szukasz: {searchQuery}</p>Kiedy używać $bindable?
Dobre przypadki:
- Inputy formularza
- Komponenty kontrolowane (select, slider)
- Modal z kontrolą widoczności
Unikaj gdy:
- Jednokierunkowy przepływ danych wystarczy
- Złożona logika aktualizacji
- Wiele źródeł prawdy
Przykład: Slider
<!-- VolumeSlider.svelte -->
<script>
let { value = $bindable(50), min = 0, max = 100 } = $props();
</script>
<div class="slider">
<input
type="range"
bind:value
{min}
{max}
/>
<span>{value}</span>
</div>
<style>
.slider {
display: flex;
align-items: center;
gap: 1rem;
}
</style><!-- Parent.svelte -->
<script>
import VolumeSlider from './VolumeSlider.svelte';
let warHornVolume = $state(75);
</script>
<h3>Głośność rogu wojennego</h3>
<VolumeSlider bind:value={warHornVolume} />
<p>Aktualna głośność: {warHornVolume}%</p>Przykład: Modal
<!-- Modal.svelte -->
<script>
let { open = $bindable(false), title, children } = $props();
function close() {
open = false;
}
</script>
{#if open}
<div class="overlay" role="presentation" onclick={close}>
<div
class="modal"
role="dialog"
aria-modal="true"
tabindex="-1"
onclick={(e) => e.stopPropagation()}
onkeydown={(e) => e.key === 'Escape' && close()}
>
<header>
<h2>{title}</h2>
<button onclick={close}>×</button>
</header>
<main>
{@render children()}
</main>
</div>
</div>
{/if}Kliknięcie w tło zamyka okno, a e.stopPropagation() (dawniej modyfikator |stopPropagation) sprawia, że kliknięcie wewnątrz okna nie dociera do tła.
<!-- Parent.svelte -->
<script>
import Modal from './Modal.svelte';
let showModal = $state(false);
</script>
<button onclick={() => showModal = true}>
Otwórz modal
</button>
<Modal bind:open={showModal} title="Rada wojenna">
<p>Planujemy atak na świcie!</p>
</Modal>Kod do tej lekcji: App.svelte
<script>
// $bindable: the child changes the parent's state through bind:value
import CoinCounter from './CoinCounter.svelte';
let treasury = $state({ gold: 10, silver: 25, copper: 40 });
let worth = $derived(treasury.gold * 100 + treasury.silver * 10 + treasury.copper);
</script>
<main class="treasury">
<h1>Viking Treasury</h1>
<p>$bindable props: each counter writes straight into the chest</p>
<div class="counters">
<CoinCounter name="Gold" bind:value={treasury.gold} />
<CoinCounter name="Silver" bind:value={treasury.silver} />
<CoinCounter name="Copper" bind:value={treasury.copper} />
</div>
<div class="total">
<h2>Worth in copper: {worth}</h2>
<button onclick={() => (treasury = { gold: 0, silver: 0, copper: 0 })}>
Empty the chest
</button>
</div>
</main>
<style>
.treasury {
font-family: 'Georgia', serif;
max-width: 600px;
margin: 0 auto;
padding: 2rem;
background: #1a0f0a;
color: #e8d5b7;
min-height: 100vh;
}
h1 {
color: #d4af37;
text-align: center;
}
p {
text-align: center;
color: #8b7355;
}
.counters {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin: 2rem 0;
}
.total {
text-align: center;
background: rgba(212, 175, 55, 0.2);
border: 2px solid #d4af37;
border-radius: 8px;
padding: 1rem;
}
.total h2 {
color: #ffd700;
margin: 0 0 0.75rem 0;
}
.total button {
padding: 0.5rem 1rem;
background: #3d2914;
color: #e8d5b7;
border: 1px solid #d4af37;
border-radius: 4px;
cursor: pointer;
}
</style>Hasła z dokumentacji w tej lekcji
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Jak oznaczyć prop jako bindable w Svelte 5?
Zadania praktyczne w grze
- Edytor kodu
Uzupełnij kod, aby value było bindable z domyślną wartością ''