Создание интерактивных форм

Riot.js — легковесный фреймворк для построения реактивных интерфейсов, который использует компонентный подход и декларативную синтаксис. Формы в Riot.js можно создавать и управлять ими с высокой степенью интерактивности благодаря реактивным данным и привязке событий.

Определение компонента формы

Каждая форма создается как отдельный компонент Riot.js. Компонент включает три ключевые секции:

  1. HTML-разметка — определяет структуру формы и элементы управления.
  2. Скрипт — содержит логику обработки событий и управление состоянием.
  3. CSS — отвечает за стилизацию формы.

Пример базового компонента формы:

<user-form>
  <form onsub mit={submitForm}>
    <label>
      Имя:
      <input type="text" name="name" bind={state.name}>
    </label>
    <label>
      Email:
      <input type="email" name="email" bind={state.email}>
    </label>
    <button type="submit">Отправить</button>
  </form>

  <p if={state.submitted}>Данные отправлены: {state.name}, {state.email}</p>

  <script>
    export default {
      state: {
        name: '',
        email: '',
        submitted: false
      },
      submitForm(event) {
        event.preventDefault();
        this.state.submitted = true;
      }
    }
  </script>

  <style>
    form { display: flex; flex-direction: column; gap: 10px; }
    label { font-weight: bold; }
    input { padding: 5px; font-size: 14px; }
    button { width: 100px; padding: 5px; }
  </style>
</user-form>

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

В Riot.js состояние компонента (state) автоматически отслеживается и обновляет интерфейс при изменениях. Для интерактивных форм это особенно важно:

  • Поля формы связываются с состоянием через bind.
  • Любое изменение данных мгновенно отражается в интерфейсе.
  • Динамическое отображение сообщений об успехе или ошибках реализуется через условные конструкции if.

Обработка событий

Riot.js позволяет легко привязывать обработчики событий к элементам формы. Основные события:

  • onsubmit — отправка формы.
  • oninput — ввод текста.
  • onclick — нажатие кнопок.
  • Пользовательские события могут быть созданы через this.trigger.

Пример динамической валидации поля email:

validateEmail() {
  const email = this.state.email;
  const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  this.state.isValidEmail = re.test(email);
}
<input type="email" name="email" bind={state.email} onin put={validateEmail}>
<p if={!state.isValidEmail && state.email.length}>Некорректный email</p>

Динамическое добавление полей

Riot.js поддерживает реактивные массивы для создания повторяющихся элементов формы. Например, список телефонов:

state: {
  phones: ['']
},
addPhone() {
  this.state.phones.push('');
},
removePhone(index) {
  this.state.phones.splice(index, 1);
}
<div each={phone, index in state.phones}>
  <input type="text" bind={state.phones[index]}>
  <button type="button" oncl ick={() => removePhone(index)}>Удалить</button>
</div>
<button type="button" oncl ick={addPhone}>Добавить телефон</button>

Интеграция с внешними API

Riot.js позволяет отправлять данные формы на сервер с использованием fetch или других библиотек. Пример отправки данных JSON:

async submitForm(event) {
  event.preventDefault();
  const response = await fetch('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: this.state.name, email: this.state.email })
  });
  if(response.ok) this.state.submitted = true;
}

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

Для сложных форм важно реализовать локальную и серверную валидацию:

  • Локальная: проверка пустых полей, формата email, длины пароля.
  • Серверная: проверка уникальности email или других данных.

Пример комбинированной валидации:

async submitForm(event) {
  event.preventDefault();
  this.state.errors = {};
  if(!this.state.name) this.state.errors.name = 'Имя обязательно';
  if(!this.state.email) this.state.errors.email = 'Email обязателен';

  if(Object.keys(this.state.errors).length) return;

  try {
    const response = await fetch('/api/users', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: this.state.name, email: this.state.email })
    });
    if(!response.ok) throw new Error('Ошибка сервера');
    this.state.submitted = true;
  } catch(e) {
    this.state.errors.server = e.message;
  }
}
<p if={state.errors.name}>{state.errors.name}</p>
<p if={state.errors.email}>{state.errors.email}</p>
<p if={state.errors.server}>{state.errors.server}</p>

Масштабирование форм

Для больших приложений формы можно разделять на подкомпоненты:

  • Поле ввода — отдельный компонент с собственной валидацией.
  • Группа полей — компонент с повторяющимися элементами.
  • Основная форма — собирает подкомпоненты и управляет состоянием.

Такой подход улучшает читаемость кода, повторное использование и поддержку.

Итоговый подход

Интерактивные формы в Riot.js строятся на сочетании:

  • Реактивного состояния (state) для мгновенного обновления интерфейса.
  • Декларативной разметки с привязкой данных (bind) и условной визуализации (if).
  • Обработчиков событий для ввода и отправки данных.
  • Подкомпонентов и реактивных массивов для масштабируемости.
  • Локальной и серверной валидации для надежности.

Этот комплексный подход позволяет создавать сложные формы с высокой интерактивностью, минимальными усилиями и чистой архитектурой.