События и функции-обработчики
Событие — сигнал от браузера: пользователь нажал кнопку, ввёл текст, отправил форму. В Svelte 5 обработчик события — обычный атрибут элемента с именем on + название события: onclick, oninput, onsubmit. В него передают функцию.
Обработчик клика
<!-- src/routes/+page.svelte -->
<script>
let count = $state(0);
function handleClick() {
count++;
}
</script>
<button onclick={handleClick}>Нажато: {count}</button>Каждый клик вызывает handleClick, и число на кнопке растёт. Передают саму функцию — без скобок. Если нужно передать аргумент, используйте стрелочную функцию: onclick={() => remove(todo.id)}.
Объект события
Обработчик получает объект события — тот же, что и в обычном JavaScript. У формы с его помощью отменяют перезагрузку страницы:
<!-- src/routes/+page.svelte -->
<script>
let todos = $state([]);
function addTodo(event) {
event.preventDefault();
const data = new FormData(event.currentTarget);
todos.push({ id: Date.now(), text: data.get('text'), done: false });
event.currentTarget.reset();
}
</script>
<form onsubmit={addTodo}>
<input name="text" placeholder="Новая задача" />
<button>Добавить</button>
</form>
<p>Задач: {todos.length}</p>Введите текст и нажмите Enter или кнопку — счётчик вырастет, а поле очистится. Модификаторов вроде |preventDefault из Svelte 4 больше нет: всё делается внутри функции.
Функция в свойстве
Дочерний компонент не меняет чужие данные, а сообщает родителю о событии. Для этого родитель передаёт ему функцию как обычное свойство. По соглашению имя такого свойства тоже начинают с on:
<!-- src/lib/components/TodoItem.svelte -->
<script>
let { todo, ontoggle, ondelete } = $props();
</script>
<li>
<input type="checkbox" checked={todo.done} onchange={() => ontoggle(todo.id)} />
{todo.text}
<button onclick={() => ondelete(todo.id)}>Удалить</button>
</li>Компонент только вызывает полученные функции и передаёт им id задачи.
Использование в родителе
<!-- src/routes/+page.svelte -->
<script>
import TodoItem from '$lib/components/TodoItem.svelte';
let todos = $state([
{ id: 1, text: 'Купить хлеб', done: false },
{ id: 2, text: 'Позвонить Олегу', done: false }
]);
function toggle(id) {
const todo = todos.find((t) => t.id === id);
todo.done = !todo.done;
}
function remove(id) {
todos = todos.filter((t) => t.id !== id);
}
</script>
<ul>
{#each todos as todo (todo.id)}
<TodoItem {todo} ontoggle={toggle} ondelete={remove} />
{/each}
</ul>Щелчок по чекбоксу меняет статус задачи в массиве родителя, кнопка «Удалить» убирает строку. Данные хранятся и меняются в одном месте — в +page.svelte.
Частая ошибка
Вызвать функцию вместо того, чтобы передать её:
<!-- src/lib/components/TodoItem.svelte: неправильно -->
<button onclick={remove(todo.id)}>Удалить</button>Здесь remove выполнится сразу при выводе разметки и удалит задачу, а в onclick попадёт результат вызова. Оборачивайте вызов с аргументами в стрелочную функцию: onclick={() => remove(todo.id)}.