Передача событий от потомка к родителю

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

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

Slim.js использует стандартную модель DOM-событий, но добавляет удобный синтаксис для работы с компонентами. События могут быть кастомными (CustomEvent) и привязываться к элементам через директиву @event в шаблоне. Важно различать два уровня:

  • Внутренние события компонента — локальные изменения состояния или пользовательские действия внутри компонента.
  • События для родителя — события, которые должны сигнализировать родительскому компоненту о том, что произошло действие в потомке.

Создание кастомного события в потомке

Для передачи данных родителю используется класс CustomEvent. Пример:

import { Slim } from 'slim-js';

class ChildComponent extends Slim {
  constructor() {
    super();
    this.message = 'Привет от потомка';
  }

  sendMessage() {
    this.dispatchEvent(new CustomEvent('child-message', {
      detail: { text: this.message },
      bubbles: true, // позволяет событию всплывать к родителю
      composed: true // разрешает прохождение через Shadow DOM
    }));
  }

  get template() {
    return `<button @click="sendMessage">Отправить сообщение</button>`;
  }
}

Slim.define('child-component', ChildComponent);

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

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

Подписка на событие в родительском компоненте

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

import { Slim } from 'slim-js';

class ParentComponent extends Slim {

  handleChildMessage(event) {
    console.log('Сообщение от потомка:', event.detail.text);
  }

  get template() {
    return `
      <child-component @child-message="handleChildMessage"></child-component>
    `;
  }
}

Slim.define('parent-component', ParentComponent);

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

  • Использование @child-message="handleChildMessage" автоматически привязывает метод к событию.
  • event.detail содержит данные, переданные из потомка.
  • Slim.js обеспечивает автоматическое удаление слушателей при уничтожении компонента, предотвращая утечки памяти.

Передача событий через несколько уровней

Если структура компонентов вложенная, события можно передавать через промежуточные компоненты. Для этого важно правильно настроить bubbles и composed:

this.dispatchEvent(new CustomEvent('child-message', {
  detail: { text: 'Данные' },
  bubbles: true,
  composed: true
}));

Любой компонент выше по дереву, который слушает @child-message, сможет получить событие, независимо от того, находится ли оно за Shadow DOM.

Передача данных с обратной связью

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

class ChildComponent extends Slim {
  message = '';

  updateMessage(newMessage) {
    this.message = newMessage;
  }

  get template() {
    return `<div>Сообщение: ${this.message}</div>`;
  }
}

class ParentComponent extends Slim {
  handleChildMessage(event) {
    const child = this.querySelector('child-component');
    child.updateMessage(event.detail.text + ' (обновлено родителем)');
  }

  get template() {
    return `<child-component @child-message="handleChildMessage"></child-component>`;
  }
}

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

Рекомендации по архитектуре событий

  1. Использовать кастомные события вместо прямого изменения состояния дочернего компонента.
  2. Всегда устанавливать bubbles: true для событий, которые должны быть видны родителю.
  3. Применять composed: true, если компоненты используют Shadow DOM.
  4. Разделять события по смыслу и именовать их ясно, например child-message, item-selected.
  5. Избегать передачи слишком больших объектов через detail, предпочтительно передавать минимальный набор данных.

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