Модель событий в Polymer

Модель событий в Polymer строится на основе стандартной DOM-архитектуры событий, расширенной механизмами, специфичными для веб-компонентов. Основная цель — обеспечить взаимодействие компонентов между собой и с внешним DOM, сохраняя инкапсуляцию и предсказуемость поведения.

События в DOM и их всплытие

В основе лежит стандартное поведение событий в браузере: события могут всплывать (bubbling) или перехватываться на фазе захвата (capturing). В Polymer используется этот механизм в полной мере, но добавляются особенности для работы с теневым DOM:

  • Bubbling (всплытие): событие, сгенерированное внутри компонента, поднимается вверх по иерархии DOM до document.
  • Composed (составные события): по умолчанию события в теневом DOM не выходят за пределы компонента. Свойство composed: true позволяет событию пройти через границы теневого DOM. Это критично для связи инкапсулированных компонентов с внешним миром.

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

this.dispatchEvent(new CustomEvent('user-logged-in', {
  detail: { userId: 42 },
  bubbles: true,
  composed: true
}));
  • detail — объект с дополнительной информацией.
  • bubbles: true — событие будет всплывать.
  • composed: true — событие выйдет за пределы теневого DOM.

Обработка событий

Для обработки событий в Polymer применяются два основных подхода: обработчики в шаблоне и прямое добавление слушателей через JavaScript.

  1. Обработчики в шаблоне:
<dom-module id="user-card">
  <template>
    <button on-click="handleClick">Нажми меня</button>
  </template>
  <script>
    class UserCard extends Polymer.Element {
      static get is() { return 'user-card'; }

      handleClick(e) {
        console.log('Кнопка нажата', e);
      }
    }
    customElements.define(UserCard.is, UserCard);
  </script>
</dom-module>
  • Событие указывается через on-eventName, где eventName — имя события.
  • Методы обработчиков объявляются в классе компонента.
  • Такой подход позволяет автоматически связывать события с внутренними методами компонента.
  1. Прямое добавление слушателей через JavaScript:
this.addEventListener('user-logged-in', e => {
  console.log('Пользователь вошёл', e.detail.userId);
});
  • Используется для динамической привязки или событий, не определённых в шаблоне.
  • Можно указывать флаги capture и once:
this.addEventListener('user-logged-in', e => { ... }, { capture: true, once: true });

Поддержка свойств событий Polymer

Polymer вводит концепцию обработки событий с привязкой к свойствам. Это позволяет изменять состояние компонента на основе приходящих событий без прямого вызова методов.

Пример:

<my-input value="{{username::input}}"></my-input>
  • Двойная привязка {{}} обеспечивает синхронизацию свойства username с событием input.
  • Суффикс ::eventName указывает, какое событие использовать для обновления свойства.

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

Пользовательские события и их композиция

Polymer активно использует CustomEvent для создания событий, которые:

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

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

class ChildElement extends Polymer.Element {
  fireUserAction(data) {
    this.dispatchEvent(new CustomEvent('user-action', {
      detail: data,
      bubbles: true,
      composed: true
    }));
  }
}

class ParentElement extends Polymer.Element {
  connectedCallback() {
    super.connectedCallback();
    this.addEventListener('user-action', e => {
      console.log('Данные от ребёнка:', e.detail);
    });
  }
}

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

  • Всегда указывать composed: true для событий, которые должны выйти за пределы компонента.
  • Использовать bubbles: true для событий, которые должны достигать родительских элементов.
  • Для реактивного связывания свойств применять {{property::event}}, что упрощает управление состоянием.
  • Предпочтительно использовать CustomEvent вместо нативных событий, если требуется передача данных или особое поведение.

Итоговая схема взаимодействия

  1. Событие создаётся в компоненте через dispatchEvent.
  2. Свойство bubbles определяет всплытие вверх по DOM.
  3. Свойство composed определяет, проходит ли событие через теневой DOM.
  4. Обработчик получает событие и извлекает данные из detail.
  5. Привязка свойств автоматически обновляет состояние компонентов при использовании директивы ::event.

Модель событий в Polymer сочетает стандартные механизмы DOM с расширениями для работы с инкапсуляцией компонентов и реактивными свойствами, что делает взаимодействие между компонентами гибким, предсказуемым и удобным для построения сложных интерфейсов.