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

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


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

В Polymer пользовательское событие создаётся с помощью конструктора CustomEvent. Основной синтаксис:

let event = new CustomEvent('имя_события', {
  detail: { /* данные события */ },
  bubbles: true,
  composed: true
});
this.dispatchEvent(event);
  • detail — объект, содержащий данные, которые передаются слушателям события. Это ключевой способ обмена информацией между компонентами.
  • bubbles — определяет, будет ли событие всплывать по DOM-дереву. Если true, событие может быть поймано родительскими элементами.
  • composed — позволяет событию проходить через Shadow DOM границы. Без этой опции событие останется локальным для компонента.

Отправка события

Внутри компонента Polymer пользовательское событие чаще всего вызывается при изменении состояния или действия пользователя:

this.dispatchEvent(new CustomEvent('user-logged-in', {
  detail: { username: this.username },
  bubbles: true,
  composed: true
}));

Здесь событие user-logged-in может быть поймано родительскими компонентами или любым элементом, который находится выше в DOM-структуре.


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

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

1. Через шаблон

В Polymer используются специальные атрибуты для связывания событий с методами:

<my-button on-click="handleClick"></my-button>

Для пользовательских событий применяется префикс on- и имя события в kebab-case:

<user-form on-user-logged-in="handleUserLoggedIn"></user-form>

Метод handleUserLoggedIn будет получать объект события как аргумент:

handleUserLoggedIn(event) {
  console.log(event.detail.username);
}

2. Через программный код

С помощью addEventListener событие можно отслеживать динамически:

this.addEventListener('user-logged-in', (event) => {
  console.log(event.detail.username);
});

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


Параметры bubbles и composed

Эти два флага имеют критическое значение для взаимодействия компонентов:

  • bubbles: если true, событие распространяется вверх по DOM-дереву. Всплытие позволяет родительским компонентам реагировать на действия детей без прямой связи.
  • composed: если true, событие может покинуть Shadow DOM и быть доступным вне инкапсуляции компонента. Без composed: true родительские элементы не увидят событие, если компонент находится внутри Shadow DOM.

Пример использования:

this.dispatchEvent(new CustomEvent('data-updated', {
  detail: { newValue: this.value },
  bubbles: true,
  composed: true
}));

Рекомендации по именованию событий

  • Использовать kebab-case для имен событий: user-logged-in, data-updated.
  • События должны отражать действие, а не состояние. Например, data-changed вместо data-state.
  • Избегать конфликтов с нативными DOM-событиями (например, click, input, change).

Передача сложных данных

Объект detail может содержать любую структуру данных: объекты, массивы, примитивы. Рекомендуется использовать простые и легко сериализуемые структуры:

this.dispatchEvent(new CustomEvent('cart-updated', {
  detail: {
    items: [
      { id: 1, name: 'Item A', quantity: 2 },
      { id: 2, name: 'Item B', quantity: 1 }
    ],
    total: 300
  },
  bubbles: true,
  composed: true
}));

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

Пользовательские события в Polymer позволяют строить иерархию компонентов с четко определёнными каналами связи:

<parent-component>
  <child-component on-action-triggered="handleAction"></child-component>
</parent-component>
handleAction(event) {
  console.log('Данные из дочернего компонента:', event.detail);
}

Таким образом, родительский компонент реагирует на события дочернего без прямого вызова методов или доступа к внутреннему состоянию дочернего элемента.


Использование событий для обратного связывания (two-way binding)

Пользовательские события часто применяются для реализации обратного связывания данных между компонентами:

this.dispatchEvent(new CustomEvent('value-changed', {
  detail: { value: this.value },
  bubbles: true,
  composed: true
}));

Если компонент подключён через Polymer binding в родителе:

<custom-input value="{{parentValue::value-changed}}"></custom-input>

Изменение внутри дочернего элемента автоматически обновляет переменную parentValue в родительском компоненте.


Отличие от нативных событий

  • Пользовательские события не ограничены заранее определённым списком событий браузера.
  • Они могут содержать произвольные данные в detail.
  • Позволяют эффективно работать внутри Shadow DOM, управляя всплытием и композицией.

Пользовательские события в Polymer обеспечивают гибкое и мощное взаимодействие компонентов, позволяя строить сложные интерфейсы с минимальной связностью и максимальной модульностью. Правильное использование detail, bubbles и composed позволяет создать надёжную систему обмена данными между компонентами в любых условиях.