Формы и input-элементы

SvelteKit предоставляет удобный способ работы с формами и input-элементами, сочетая реактивность Svelte с мощью современных UI-библиотек. Основной подход заключается в связывании состояния формы с переменными компонента через двустороннюю привязку (bind:value). Это позволяет автоматически обновлять значения input-полей при изменении состояния и наоборот.

<script>
  let username = '';
  let email = '';
</script>

<form on:submit|preventDefault={() => console.log({ username, email })}>
  <label>
    Имя пользователя:
    <input type="text" bind:value={username} placeholder="Введите имя">
  </label>

  <label>
    Email:
    <input type="email" bind:value={email} placeholder="Введите email">
  </label>

  <button type="submit">Отправить</button>
</form>

Ключевые моменты:

  • Использование bind:value обеспечивает реактивность без необходимости вручную обновлять состояние.
  • Модификатор |preventDefault предотвращает стандартное поведение отправки формы.
  • Каждое поле можно валидировать как на клиенте, так и на сервере, интегрируя с actions SvelteKit.

Валидация и обработка ошибок

Валидация форм может выполняться на нескольких уровнях: встроенные HTML-атрибуты (required, pattern, minlength) и кастомная логика в скрипте компонента. Для крупных форм лучше использовать отдельный объект состояния ошибок.

<script>
  let username = '';
  let email = '';
  let errors = {};

  function validate() {
    errors = {};
    if (!username) errors.username = 'Имя обязательно';
    if (!email.includes('@')) errors.email = 'Неверный формат email';
    return Object.keys(errors).length === 0;
  }

  function handleSubmit() {
    if (validate()) {
      console.log('Форма валидна:', { username, email });
    }
  }
</script>

<form on:submit|preventDefault={handleSubmit}>
  <label>
    Имя пользователя:
    <input type="text" bind:value={username}>
    {#if errors.username}<span class="error">{errors.username}</span>{/if}
  </label>

  <label>
    Email:
    <input type="email" bind:value={email}>
    {#if errors.email}<span class="error">{errors.email}</span>{/if}
  </label>

  <button type="submit">Отправить</button>
</form>

Особенности подхода:

  • Использование реактивного объекта errors позволяет динамически показывать ошибки рядом с полями.
  • Возможна интеграция с внешними UI-библиотеками для отображения ошибок через компоненты типа Alert или Tooltip.

Input-элементы и кастомизация

SvelteKit UI-библиотеки, такие как Svelte Material UI (SMUI) или SvelteStrap, предоставляют готовые компоненты input, checkbox, radio и sel ect с расширенными возможностями стилизации и валидации.

Пример использования SMUI TextField:

<script>
  import TextField fr om '@smui/textfield';
  let password = '';
</script>

<TextField
  bind:value={password}
  type="password"
  label="Пароль"
  outlined
  required
/>

Преимущества кастомных компонентов:

  • Поддержка темизации и стилей из библиотеки.
  • Автоматическая интеграция с реактивностью Svelte (bind:value работает без дополнительного кода).
  • Встроенные свойства для управления состоянием (disabled, error, helperText).

Работа с checkbox и radio

Checkbox и radio-кнопки также легко интегрируются с состоянием компонента. Для checkbox часто используют булевы значения, а для radio — один общий bind:group.

<script>
  let acceptTerms = false;
  let gender = '';
</script>

<label>
  <input type="checkbox" bind:checked={acceptTerms}>
  Согласен с условиями
</label>

<label>
  <input type="radio" bind:group={gender} value="male"> Мужской
</label>
<label>
  <input type="radio" bind:group={gender} value="female"> Женский
</label>

Важные нюансы:

  • Для checkbox используется bind:checked, а не bind:value.
  • Radio-кнопки объединяются с помощью одного bind:group, что обеспечивает корректное поведение выбора.

Select, multi-select и динамические опции

Для select-элементов применяются стандартные HTML-теги <select> или компоненты UI-библиотек, поддерживающие мультивыбор. Динамическое создание опций через массив данных делает код более универсальным.

<script>
  let selectedCountry = '';
  const countries = ['Россия', 'США', 'Германия'];
</script>

<select bind:value={selectedCountry}>
  <option value="">Выберите страну</option>
  {#each countries as country}
    <option value={country}>{country}</option>
  {/each}
</select>

Для multi-select, например в SMUI:

<script>
  import Select fr om '@smui/select';
  let selectedFruits = [];
  const fruits = ['Яблоко', 'Банан', 'Груша'];
</script>

<Select bind:value={selectedFruits} multiple>
  {#each fruits as fruit}
    <option value={fruit}>{fruit}</option>
  {/each}
</Select>

Особенности:

  • Использование multiple позволяет сохранять несколько значений в массив.
  • Реактивные массивы автоматически обновляются при добавлении/удалении элементов.

Интеграция с формами SvelteKit Actions

SvelteKit Actions позволяют обрабатывать отправку форм на сервере без перезагрузки страницы. Input-значения передаются через formData, а результаты можно возвращать в компонент для отображения ошибок или успешной отправки.

<script context="module">
  export const actions = {
    default: async ({ request }) => {
      const data = await request.formData();
      const username = data.get('username');
      if (!username) return { errors: { username: 'Имя обязательно' } };
      return { success: true };
    }
  };
</script>

<form method="POST" use:enhance>
  <input name="username" type="text">
  <button type="submit">Отправить</button>
</form>

Преимущества подхода:

  • Отправка формы асинхронно, без полной перезагрузки страницы.
  • Серверная валидация интегрирована с клиентской реактивностью.
  • Легко комбинировать с кастомными UI-компонентами для динамического отображения ошибок.

Реактивное управление состоянием формы

В сложных приложениях состояние формы часто организуют через объект form, где каждый ключ соответствует полю. Это упрощает работу с динамическими формами и компонентами UI-библиотек.

<script>
  let form = {
    username: '',
    email: '',
    password: ''
  };
</script>

<input type="text" bind:value={form.username} placeholder="Имя">
<input type="email" bind:value={form.email} placeholder="Email">
<input type="password" bind:value={form.password} placeholder="Пароль">

Преимущества:

  • Унифицированный объект состояния для всех полей.
  • Удобно передавать данные на сервер или в кастомные функции обработки.
  • Возможность динамически добавлять новые поля без изменения структуры компонента.