Работа с event.detail

Slim.js — это современная библиотека для создания компонент на JavaScript, обеспечивающая лёгкую реактивность и декларативный рендеринг. Одной из ключевых возможностей является работа с кастомными событиями и передачей данных через объект event.detail.


Основы event.detail

В DOM существует встроенный механизм событий через Event и его наследников (CustomEvent, MouseEvent и другие). Для передачи данных внутри событий в Slim.js используется объект detail, доступный при создании CustomEvent.

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

const event = new CustomEvent('user-selected', {
  detail: { id: 42, name: 'Alice' },
  bubbles: true,
  composed: true
});

element.dispatchEvent(event);

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

  • detail может содержать любые данные: объекты, массивы, примитивные типы.
  • bubbles: true позволяет событию подниматься вверх по DOM.
  • composed: true позволяет событию выходить из Shadow DOM.

Обработка событий в Slim.js

В Slim.js привязка обработчиков событий осуществляется через атрибут @event, где event — имя события.

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

import { Slim, html } from 'slim-js';

class UserList extends Slim {
  users = [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' }
  ];

  selectUser(user) {
    this.dispatchEvent(new CustomEvent('user-selected', {
      detail: user,
      bubbles: true,
      composed: true
    }));
  }

  render() {
    return html`
      <ul>
        ${this.users.map(user => html`
          <li @click="${() => this.selectUser(user)}">${user.name}</li>
        `)}
      </ul>
    `;
  }
}

Slim.define('user-list', UserList);

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


Получение event.detail в родительских компонентах

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

class AppRoot extends Slim {
  handleUserSelected(event) {
    console.log('Выбран пользователь:', event.detail);
  }

  render() {
    return html`
      <user-list @user-selected="${this.handleUserSelected}"></user-list>
    `;
  }
}

Slim.define('app-root', AppRoot);

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

  • event.detail всегда содержит именно те данные, которые были переданы при CustomEvent.
  • Slim.js автоматически связывает контекст this с компонентом, если обработчик объявлен как метод класса.

Типовые сценарии использования

  1. Передача данных между компонентами

event.detail часто используется для передачи состояния из дочернего компонента в родительский.

Пример: выбор элемента списка, настройка формы, уведомление об изменении состояния.

  1. Декларативная реактивность

Slim.js позволяет использовать event.detail внутри шаблонов для динамического изменения интерфейса.

handleUserSelected(event) {
  this.selectedUser = event.detail;
}

При этом selectedUser автоматически обновляет шаблон, если используется в рендере.

  1. Комбинированные события

В сложных интерфейсах одно событие может содержать несколько параметров, передаваемых через объект:

this.dispatchEvent(new CustomEvent('item-action', {
  detail: { itemId: 5, action: 'delete' },
  bubbles: true
}));

Родительский компонент извлекает нужные данные:

handleItemAction(event) {
  const { itemId, action } = event.detail;
  if(action === 'delete') {
    this.deleteItem(itemId);
  }
}

Взаимодействие с Shadow DOM

Если компонент использует Shadow DOM, composed: true в CustomEvent делает событие доступным за пределами теневого дерева:

const event = new CustomEvent('notify', {
  detail: { message: 'Привет' },
  bubbles: true,
  composed: true
});
this.shadowRoot.dispatchEvent(event);

Без composed: true событие не поднимется за пределы Shadow DOM.


Советы по использованию event.detail в Slim.js

  • Всегда использовать объекты для detail, даже если передаётся один параметр — это упрощает расширение события в будущем.
  • Для часто используемых событий можно создавать собственные вспомогательные функции:
function dispatchUserSelected(el, user) {
  el.dispatchEvent(new CustomEvent('user-selected', {
    detail: user,
    bubbles: true,
    composed: true
  }));
}
  • Для компонентов с большим количеством событий рекомендуется документировать формат detail, чтобы упростить интеграцию между разработчиками.

Сравнение с обычными DOM-событиями

  • event.detail уникален для CustomEvent и отсутствует в стандартных событиях, таких как click или input.
  • Slim.js обеспечивает удобную привязку событий через атрибуты шаблона @event, что сокращает boilerplate по сравнению с addEventListener.
  • Использование detail делает события самодостаточными — все данные передаются внутри события, без необходимости хранить состояние в глобальных переменных.

Практический пример: фильтрация списка

class FilterList extends Slim {
  items = ['Apple', 'Banana', 'Orange'];

  filterItems(query) {
    const filtered = this.items.filter(item => item.toLowerCase().includes(query.toLowerCase()));
    this.dispatchEvent(new CustomEvent('filter-applied', {
      detail: { query, filtered },
      bubbles: true
    }));
  }

  render() {
    return html`
      <input type="text" @input="${e => this.filterItems(e.target.value)}" placeholder="Фильтр">
      <ul>
        ${this.items.map(item => html`<li>${item}</li>`)}
      </ul>
    `;
  }
}

Slim.define('filter-list', FilterList);

Родительский компонент может получить и использовать данные фильтрации:

handleFilter(event) {
  console.log('Поиск:', event.detail.query);
  console.log('Результаты:', event.detail.filtered);
}

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