Обработка ввода пользователя

SkateJS — это библиотека для создания веб-компонентов на основе стандартов Custom Elements, которая обеспечивает декларативное управление состоянием и событиями. Обработка ввода пользователя в SkateJS строится на двух ключевых концептах: событиях DOM и реактивных свойствах компонентов. Комбинация этих механизмов позволяет эффективно связывать пользовательский ввод с внутренним состоянием компонента и его представлением.


Работа с событиями

SkateJS использует стандартные DOM-события, при этом позволяет их легко связывать с методами компонента через объект events. Пример базового синтаксиса:

import { define, props, Component } from 'skatejs';

class InputComponent extends Component {
  static get props() {
    return {
      value: props.string
    };
  }

  static get events() {
    return {
      input: 'handleInput',
      keyup: 'handleKeyUp'
    };
  }

  handleInput(event) {
    this.value = event.target.value;
  }

  handleKeyUp(event) {
    console.log('Нажата клавиша:', event.key);
  }

  renderCallback() {
    return <input value={this.value} />;
  }
}

define(InputComponent);

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

  • Свойство events позволяет напрямую привязать DOM-событие к методу класса, что устраняет необходимость ручного добавления слушателей через addEventListener.
  • Методы-обработчики получают объект события event, стандартный для DOM.
  • Все изменения, происходящие в обработчиках, автоматически могут отражаться на состоянии компонента через реактивные свойства.

Реактивные свойства и двусторонняя привязка

В SkateJS свойства компонента описываются через props. Эти свойства обладают реактивностью: любое изменение значения инициирует обновление рендеринга. Это позволяет реализовать двустороннюю привязку с элементами формы.

class TextareaComponent extends Component {
  static get props() {
    return {
      text: props.string
    };
  }

  handleChange(event) {
    this.text = event.target.value;
  }

  renderCallback() {
    return (
      <textarea value={this.text} onIn put={this.handleChange.bind(this)}></textarea>
    );
  }
}

define(TextareaComponent);

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

  • Свойства, определённые через props, автоматически отслеживают изменения.
  • Любое обновление свойства через обработчик события вызывает повторный рендеринг компонента.
  • Использование bind(this) гарантирует корректный контекст внутри метода.

Валидация и ограничение ввода

Для сложных форм часто требуется проверка введённых данных. В SkateJS это реализуется через методы компонента и реактивные свойства. Можно хранить статус валидности в отдельном свойстве:

class FormComponent extends Component {
  static get props() {
    return {
      email: props.string,
      isValid: props.boolean
    };
  }

  validateEmail(value) {
    const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    this.isValid = pattern.test(value);
  }

  handleInput(event) {
    this.email = event.target.value;
    this.validateEmail(this.email);
  }

  renderCallback() {
    return (
      <div>
        <input type="email" value={this.email} onIn put={this.handleInput.bind(this)} />
        <span>{this.isValid ? 'Адрес корректен' : 'Некорректный email'}</span>
      </div>
    );
  }
}

define(FormComponent);

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

  • Реактивное свойство isValid позволяет динамически обновлять интерфейс при изменении данных.
  • Метод validateEmail может быть расширен для любых правил проверки.
  • Подход обеспечивает разделение логики валидации и отображения.

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

SkateJS позволяет легко обрабатывать различные клавиши и комбинации. Для этого используется объект KeyboardEvent:

class KeyListenerComponent extends Component {
  handleKeyDown(event) {
    if (event.key === 'Enter') {
      console.log('Нажата Enter');
    } else if (event.ctrlKey && event.key === 'S') {
      event.preventDefault();
      console.log('Сохранение данных');
    }
  }

  renderCallback() {
    return <input onKeyD own={this.handleKeyDown.bind(this)} />;
  }
}

define(KeyListenerComponent);

Важные моменты:

  • Свойства event.key, event.ctrlKey, event.shiftKey и другие позволяют гибко определять действия пользователя.
  • Использование preventDefault() предотвращает стандартное поведение браузера при определённых комбинациях клавиш.

Композиция и повторное использование обработчиков

В SkateJS удобно выносить обработчики в отдельные методы или даже утилитарные функции для повторного использования:

function logInputChange(component, event) {
  component.value = event.target.value;
  console.log('Текущее значение:', component.value);
}

class ReusableInput extends Component {
  static get props() {
    return {
      value: props.string
    };
  }

  handleInput(event) {
    logInputChange(this, event);
  }

  renderCallback() {
    return <input value={this.value} onIn put={this.handleInput.bind(this)} />;
  }
}

define(ReusableInput);

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

  • Централизация логики упрощает поддержку и тестирование.
  • Повторное использование функций позволяет создавать единый стиль обработки ввода в проекте.
  • Свойства компонента остаются реактивными при любых изменениях через утилиты.

Обработка сложных форм

Для форм с несколькими полями SkateJS обеспечивает удобное связывание каждого поля с отдельным свойством компонента:

class MultiFieldForm extends Component {
  static get props() {
    return {
      firstName: props.string,
      lastName: props.string,
      age: props.number
    };
  }

  handleChange(prop, event) {
    this[prop] = event.target.value;
  }

  renderCallback() {
    return (
      <form>
        <input
          value={this.firstName}
          onIn put={this.handleChange.bind(this, 'firstName')}
          placeholder="Имя"
        />
        <input
          value={this.lastName}
          onIn put={this.handleChange.bind(this, 'lastName')}
          placeholder="Фамилия"
        />
        <input
          type="number"
          value={this.age}
          onIn put={this.handleChange.bind(this, 'age')}
          placeholder="Возраст"
        />
      </form>
    );
  }
}

define(MultiFieldForm);

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

  • Универсальный метод handleChange снижает дублирование кода.
  • Каждый input связан с реактивным свойством, изменения мгновенно отражаются на состоянии компонента.
  • Возможна интеграция с валидацией и дополнительной логикой.

Интеграция с внешними событиями

SkateJS позволяет подписываться на события вне компонента, например глобальные или кастомные события:

class GlobalEventComponent extends Component {
  connectedCallback() {
    super.connectedCallback();
    window.addEventListener('resize', this.handleResize.bind(this));
  }

  disconnectedCallback() {
    window.removeEventListener('resize', this.handleResize.bind(this));
    super.disconnectedCallback();
  }

  handleResize(event) {
    console.log('Размер окна изменён:', window.innerWidth, window.innerHeight);
  }

  renderCallback() {
    return <div>Следим за изменением размеров окна</div>;
  }
}

define(GlobalEventComponent);

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

  • Методы connectedCallback и disconnectedCallback позволяют безопасно подписываться и отписываться от внешних событий.
  • Привязка обработчика через bind(this) сохраняет корректный контекст.
  • Такой подход обеспечивает полноценное управление любыми событиями, влияющими на компонент.