Всплытие и перехват

Atomico — это современная библиотека для создания веб-компонентов с реактивным подходом, позволяющая управлять событиями и состоянием компонентов с высокой гибкостью. Одним из ключевых аспектов взаимодействия компонентов является работа с событиями: их всплытие, перехват и обработка на разных уровнях дерева компонентов.


Природа событий в Atomico

События в Atomico строятся на стандарте CustomEvent браузера. Каждый компонент может создавать собственные события через функцию emit и подписываться на события через директиву on.

import { c, useEffect } from "atomico";

function Button() {
  const handleClick = () => {
    emit("custom-click", { detail: { value: 42 } });
  };

  return <button oncl ick={handleClick}>Нажми меня</button>;
}

Button.props = {};
export default c(Button);

В этом примере событие custom-click инициируется внутри компонента, и оно может всплывать к родительским компонентам.


Всплытие событий

В Atomico события по умолчанию всплывают, если не указано обратное через опцию bubbles: false. Всплытие означает, что событие проходит через все родительские компоненты, начиная от источника события и заканчивая корневым элементом документа.

function Parent() {
  const handleCustomClick = (event) => {
    console.log("Событие дошло до родителя:", event.detail.value);
  };

  return <child onCustom-click={handleCustomClick} />;
}

Ключевой момент — имена событий в атрибутах преобразуются в camelCase при подписке: onCustom-click соответствует событию custom-click.

Важно: всплытие в Atomico поддерживает стоп-функцию, аналогичную event.stopPropagation(), позволяющую прервать распространение события на родительские компоненты.


Перехват событий

Atomico предоставляет механизм перехвата событий с помощью свойства capture. Перехват отличается от обычной подписки тем, что событие обрабатывается на этапе прохода вниз по дереву, перед достижением целевого элемента.

function GrandParent() {
  const handleCustomClickCapture = (event) => {
    console.log("Перехват на верхнем уровне:", event.detail.value);
  };

  return <parent onCustom-clickCapture={handleCustomClickCapture} />;
}

Использование onCustom-clickCapture позволяет обрабатывать событие до того, как оно достигнет внутреннего компонента, что полезно для реализации глобальной логики или предотвращения нежелательных побочных эффектов.


Опции события

При создании события через emit можно передавать дополнительные опции:

  • bubbles — разрешает всплытие (по умолчанию true).
  • composed — разрешает прохождение через Shadow DOM (по умолчанию true).
  • cancelable — позволяет отменить стандартное действие (по умолчанию false).
emit("custom-click", {
  detail: { value: 42 },
  bubbles: true,
  composed: true,
  cancelable: true
});

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


Отмена и модификация событий

Atomico поддерживает привычные методы работы с событиями:

  • event.stopPropagation() — останавливает всплытие события дальше по дереву.
  • event.preventDefault() — предотвращает стандартное действие, если cancelable установлен в true.
function Child() {
  const handleClick = (event) => {
    event.stopPropagation();
    console.log("Событие обработано внутри компонента");
  };

  return <button onCustom-click={handleClick}>Клик</button>;
}

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


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

Atomico активно использует Shadow DOM, и события могут быть composed или не composed:

  • Если composed: true, событие выходит из Shadow DOM и становится доступным внешнему документу.
  • Если composed: false, событие остается внутри Shadow DOM компонента.
emit("custom-click", { detail: {}, composed: false });

Это важно для инкапсуляции логики компонентов, чтобы внутренние события не случайно не влияли на внешние компоненты.


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

  1. Внутренние события для управления состоянием: дочерние компоненты уведомляют родителя о изменениях, используя всплытие.
  2. Глобальные перехваты событий: родительские компоненты перехватывают события на этапе capture для логирования или контроля.
  3. Изоляция логики через Shadow DOM: отключение composed для локальных событий, чтобы они не просачивались наружу.
  4. Комбинация capture и stopPropagation: для сложных интерфейсов с вложенными компонентами, чтобы гарантировать обработку только на нужном уровне.

Итоговое понимание

Всплытие и перехват в Atomico — это комбинация стандарта DOM-событий и реактивного подхода библиотеки. Владение этими механизмами позволяет создавать гибкие и изолированные компоненты, контролировать взаимодействие между слоями приложения и строить сложные интерфейсы без конфликтов событий.

Ключевые моменты для работы:

  • emit с правильными опциями (bubbles, composed, cancelable).
  • Подписка через onEvent и onEventCapture.
  • Использование stopPropagation и preventDefault для управления потоками событий.
  • Понимание влияния Shadow DOM на доступность события.