Объявление событий

SkateJS — библиотека для создания веб-компонентов на основе стандартов Custom Elements. Управление событиями является ключевой частью взаимодействия компонентов друг с другом и с внешним окружением. В SkateJS событийная модель строится поверх стандартного DOM, что позволяет использовать привычные методы dispatchEvent и addEventListener, но с дополнительными возможностями, предоставляемыми самим фреймворком.

Основы событийной модели

Каждый компонент SkateJS может инициировать события с помощью метода emit. Этот метод упрощает создание и распространение кастомных событий, обеспечивая удобный синтаксис и автоматическое управление деталями, такими как bubbles и composed.

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

import { Component, h } from 'skatejs';

class MyButton extends Component {
  static get is() { return 'my-button'; }

  clickHandler() {
    this.emit('button-clicked', { detail: { time: Date.now() } });
  }

  render() {
    return <button oncl ick={() => this.clickHandler()}>Нажми меня</button>;
  }
}

customElements.define(MyButton.is, MyButton);

Здесь событие button-clicked создается и автоматически передается в родительский DOM. Опция detail позволяет передавать любые данные вместе с событием.

Параметры событий

Метод emit поддерживает несколько ключевых параметров:

  • detail — объект с пользовательскими данными, доступными через event.detail.
  • bubbles — булево значение, определяющее, будет ли событие всплывать по дереву DOM (по умолчанию true).
  • composed — определяет, будет ли событие пересекать shadow DOM границы (по умолчанию true).
  • cancelable — разрешает отмену события через event.preventDefault() (по умолчанию false).

Пример с кастомными параметрами:

this.emit('data-updated', {
  detail: { value: 42 },
  bubbles: true,
  composed: true,
  cancelable: true
});

Подписка на события

Подписка на события в SkateJS может выполняться стандартными методами DOM:

document.querySelector('my-button').addEventListener('button-clicked', (event) => {
  console.log('Событие произошло в', event.detail.time);
});

Также можно использовать реактивные свойства компонента и методы SkateJS для автоматической реакции на изменения и события, что особенно полезно при построении сложных UI-компонентов.

События и Shadow DOM

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

this.emit('shadow-event', { composed: true });

Без composed: true событие останется внутри shadow root и не будет доступно внешнему DOM.

Кастомные события с синтаксисом SkateJS

Метод emit в SkateJS является оберткой над стандартным CustomEvent. Это позволяет писать компактный код без необходимости вручную создавать объекты CustomEvent. Пример сравнения:

Стандартный подход:

const event = new CustomEvent('button-clicked', { 
  detail: { time: Date.now() },
  bubbles: true,
  composed: true
});
this.dispatchEvent(event);

С SkateJS:

this.emit('button-clicked', { detail: { time: Date.now() } });

Синтаксис SkateJS сокращает количество кода, улучшает читаемость и стандартизирует обработку событий внутри компонентов.

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

  • Использовать события для уведомления внешнего мира о внутренних изменениях компонента. Не стоит смешивать события с внутренней логикой компонента.
  • Всегда определять composed: true, если событие должно быть доступно за пределами Shadow DOM.
  • Для частых событий (например, mousemove или input) лучше использовать стандартные события DOM, чтобы избежать лишней нагрузки.
  • Поддерживать консистентное именование событий — например, с использованием префиксов компонента (my-button-clicked), чтобы исключить коллизии имен.

Пример комплексного компонента

import { Component, h } from 'skatejs';

class Counter extends Component {
  static get is() { return 'my-counter'; }

  static get props() {
    return {
      count: { attribute: true, type: Number }
    };
  }

  increment() {
    this.count++;
    this.emit('count-changed', { detail: { count: this.count } });
  }

  render() {
    return (
      <div>
        <span>{this.count}</span>
        <button oncl ick={() => this.increment()}>+</button>
      </div>
    );
  }
}

customElements.define(Counter.is, Counter);

В этом примере компонент Counter уведомляет внешний код о каждом изменении счётчика через событие count-changed. Внешний DOM может реагировать на него следующим образом:

document.querySelector('my-counter').addEventListener('count-changed', (event) => {
  console.log('Текущее значение:', event.detail.count);
});

Итоговые особенности событий SkateJS

  • Унификация создания событий через emit.
  • Поддержка передачи данных через detail.
  • Полная совместимость с Shadow DOM.
  • Управление всплытием и возможностью отмены событий.
  • Чистый и компактный синтаксис по сравнению с стандартным CustomEvent.

Эта система позволяет строить реактивные и модульные компоненты, где внутренние события легко интегрируются с внешними обработчиками, а управление DOM остаётся полностью предсказуемым и стандартным.