Декларативная обработка событий

Декларативная обработка событий является одной из ключевых особенностей фреймворка Polymer. Она позволяет связывать события элементов с методами компонентов без необходимости вручную устанавливать обработчики через addEventListener. Такой подход делает код более читаемым, структурированным и безопасным с точки зрения управления жизненным циклом элементов.

Основы синтаксиса

Polymer использует атрибуты вида on-event="method" для привязки событий к методам компонента. Здесь event — это имя события, а method — имя функции, объявленной в объекте methods или внутри класса компонента.

Пример декларативной привязки события click к методу handleClick:

class MyElement extends Polymer.Element {
  static get is() { return 'my-element'; }

  handleClick(e) {
    console.log('Клик по элементу', e.target);
  }
}

customElements.define(MyElement.is, MyElement);

HTML-шаблон для компонента:

<my-element>
  <button on-click="handleClick">Нажми меня</button>
</my-element>

Важно, что событие передаётся в метод автоматически в виде объекта Event. Это позволяет работать с целевым элементом (event.target) и другими свойствами события.

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

Polymer поддерживает работу с любыми событиями: как стандартными DOM-событиями (click, input, change), так и пользовательскими (CustomEvent). Создание и отправка пользовательских событий выполняется через метод dispatchEvent:

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

Декларативная привязка пользовательских событий аналогична стандартной:

<my-element on-custom-action="handleCustomAction"></my-element>

Метод обработки:

handleCustomAction(e) {
  console.log('Пользовательское событие:', e.detail.value);
}

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

  • bubbles: true позволяет событию всплывать через дерево DOM.
  • composed: true делает событие доступным за пределами Shadow DOM.

Параметры методов обработки

Методы, привязанные через on-event, могут принимать объект события как единственный аргумент. Для передачи дополнительных данных от элемента к обработчику используются свойства компонента или атрибуты.

Пример с передачей значения из атрибута:

<button on-click="handleClick" data-id="123">Нажми</button>
handleClick(e) {
  const id = e.target.dataset.id;
  console.log('ID кнопки:', id);
}

Использование стрелочных функций

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

Неправильный пример:

handleClick = (e) => {
  console.log(this); // undefined в контексте Polymer
}

Правильный подход:

handleClick(e) {
  console.log(this); // экземпляр компонента
}

Делегирование событий

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

<div on-click="handleChildClick">
  <button data-id="1">Кнопка 1</button>
  <button data-id="2">Кнопка 2</button>
</div>

Метод:

handleChildClick(e) {
  const button = e.target.closest('button');
  if (!button) return;
  console.log('Нажата кнопка с ID:', button.dataset.id);
}

Применение с шаблонами dom-repeat

При работе с динамическими списками через <template is="dom-repeat"> декларативная привязка позволяет автоматически обрабатывать события для всех повторяющихся элементов:

<template is="dom-repeat" items="{{items}}">
  <button on-click="itemClicked" data-index$="{{index}}">{{item.name}}</button>
</template>
itemClicked(e) {
  const index = e.target.dataset.index;
  console.log('Клик по элементу списка:', this.items[index]);
}

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

Использование событий в композиции компонентов

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

<parent-element>
  <child-element on-custom-action="handleChildAction"></child-element>
</parent-element>
handleChildAction(e) {
  console.log('Событие из дочернего компонента:', e.detail);
}

Параметры bubbles: true и composed: true обеспечивают, что событие успешно достигнет родительского компонента, даже если используется Shadow DOM.

Ограничения и рекомендации

  • События, не всплывающие (bubbles: false), не могут быть обработаны на родительских компонентах.
  • Для оптимизации производительности следует избегать привязки большого количества обработчиков на уровне каждого элемента списка, используя делегирование.
  • Декларативные обработчики не могут быть асинхронными по умолчанию, однако внутри метода можно использовать async/await.

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