Создание пользовательских событий

Slim.js — это легковесная библиотека для создания компонентов веб-интерфейсов с реактивными свойствами. Одним из ключевых инструментов взаимодействия между компонентами является система событий. Помимо стандартных событий DOM, Slim.js предоставляет механизмы для создания и обработки пользовательских событий, которые позволяют компонентам обмениваться данными и реагировать на изменения состояния.

Основы пользовательских событий

Пользовательские события в Slim.js создаются с помощью метода dispatch. Этот метод позволяет компоненту генерировать событие, которое может быть перехвачено другим компонентом или родительским элементом.

Синтаксис базового вызова:

this.dispatch('имяСобытия', данные);
  • имяСобытия — строка, идентифицирующая событие.
  • данные — объект, передаваемый слушателю события.

Пример создания простого события:

class MyButton extends Slim {
  get template() {
    return `<button>Нажми меня</button>`;
  }

  onClick() {
    this.dispatch('buttonClicked', { time: new Date() });
  }

  constructor() {
    super();
    this.addEventListener('click', () => this.onClick());
  }
}

customElements.define('my-button', MyButton);

В этом примере при каждом клике по кнопке компонент MyButton генерирует событие buttonClicked с информацией о времени нажатия.

Слушатели пользовательских событий

Для обработки пользовательских событий используется стандартный метод addEventListener. Отличие заключается в том, что событие создается компонентом, а не браузером:

const button = document.querySelector('my-button');

button.addEventListener('buttonClicked', (event) => {
  console.log('Событие получено:', event.detail);
});

Здесь свойство event.detail содержит объект с данными, переданными при вызове dispatch.

Всплытие и делегирование событий

Slim.js поддерживает всплытие пользовательских событий, что позволяет организовать взаимодействие на уровне родительских компонентов. Для включения всплытия необходимо при вызове dispatch передать опцию bubbles: true:

this.dispatch('customEvent', { info: 'data' }, { bubbles: true });

Это дает возможность родительскому компоненту ловить события дочерних компонентов без явного назначения слушателя на каждый элемент:

class ParentComponent extends Slim {
  get template() {
    return `<my-button></my-button>`;
  }

  constructor() {
    super();
    this.addEventListener('customEvent', (e) => {
      console.log('Событие от дочернего компонента:', e.detail);
    });
  }
}

Настройка поведения события

Метод dispatch поддерживает объект с настройками, который может включать следующие свойства:

  • bubbles — определяет, будет ли событие всплывать.
  • cancelable — позволяет событию быть отменяемым с помощью event.preventDefault().
  • composed — делает событие доступным вне Shadow DOM.

Пример:

this.dispatch('formSubmitted', { valid: true }, { bubbles: true, cancelable: true, composed: true });

Использование этих параметров особенно важно при работе со сложными компонентами, где события должны проходить через Shadow DOM или иметь возможность блокирования действия.

Передача данных через события

Пользовательские события в Slim.js используют стандартное свойство detail для передачи данных. Это позволяет передавать объекты, массивы, строки или любые другие типы данных.

Пример передачи комплексного объекта:

this.dispatch('userUpdated', { id: 123, name: 'Иван', roles: ['admin', 'editor'] });

Обработчик может получить доступ к полям объекта через event.detail:

component.addEventListener('userUpdated', (e) => {
  console.log(e.detail.name); // Иван
  console.log(e.detail.roles); // ['admin', 'editor']
});

Пользовательские события и реактивность

Slim.js интегрирует пользовательские события с реактивными свойствами компонентов. Часто событие создается в ответ на изменение состояния:

class Counter extends Slim {
  get template() {
    return `<button>Увеличить: {{count}}</button>`;
  }

  set count(value) {
    this._count = value;
    this.dispatch('countChanged', { count: value }, { bubbles: true });
  }

  get count() {
    return this._count || 0;
  }

  constructor() {
    super();
    this.addEventListener('click', () => this.count++);
  }
}

customElements.define('my-counter', Counter);

Каждое изменение свойства count автоматически порождает событие countChanged, которое можно слушать на родительском уровне.

Практические рекомендации

  1. Для локальных событий достаточно стандартного dispatch без bubbles.
  2. Для взаимодействия между компонентами рекомендуется использовать всплытие (bubbles: true) и composed: true.
  3. Передаваемые данные лучше упаковывать в объект — это облегчает расширение и обработку событий.
  4. Для сложных компонентов стоит документировать пользовательские события, их структуру и момент генерации.

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