Делегирование событий — ключевой механизм управления взаимодействием с DOM в веб-компонентах на базе Polymer. Оно позволяет уменьшить количество обработчиков событий, повысить производительность и сделать код более модульным.
В традиционном подходе к обработке событий каждый элемент, который должен реагировать на взаимодействие пользователя, получает собственный обработчик. Это быстро становится непрактичным при большом количестве элементов:
this.shadowRoot.querySelectorAll('button').forEach(button => {
button.addEventListener('click', this._onButtonClick.bind(this));
});
Делегирование событий основано на том, что события всплывают (bubble) от дочернего элемента к родительскому. Вместо того чтобы навешивать обработчик на каждый элемент, достаточно поставить его на общий контейнер:
this.shadowRoot.querySelector('#container').addEventListener('click', this._delegateClick.bind(this));
Внутри обработчика определяется, на каком элементе произошло событие, и выполняется соответствующее действие:
_delegateClick(event) {
if (event.target.tagName === 'BUTTON') {
console.log('Нажата кнопка:', event.target.textContent);
}
}
on-* атрибутовPolymer поддерживает декларативное связывание событий через атрибуты
вида on-event. Вместо явного addEventListener
можно использовать:
<dom-module id="my-element">
<template>
<div id="container" on-click="_handleClick">
<button>Кнопка 1</button>
<button>Кнопка 2</button>
</div>
</template>
<script>
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
_handleClick(event) {
if (event.target.tagName === 'BUTTON') {
console.log('Нажата кнопка через делегирование:', event.target.textContent);
}
}
}
customElements.define(MyElement.is, MyElement);
</script>
</dom-module>
Таким образом, один обработчик на контейнере обрабатывает клики всех кнопок внутри него.
event.model для доступа к даннымКогда элементы генерируются динамически через
dom-repeat, полезно получать контекст элемента, на который
кликнули:
<template is="dom-repeat" items="{{items}}">
<div on-click="_handleItemClick">
{{item.name}}
</div>
</template>
В обработчике:
_handleItemClick(event) {
const item = event.model.item;
console.log('Клик по элементу с данными:', item);
}
event.model — это специальное свойство Polymer,
позволяющее получить доступ к данным конкретного повторяющегося
элемента, что делает делегирование особенно мощным при работе с
списками.
В Polymer используется Shadow DOM, что влияет на механизм
делегирования. События внутри Shadow DOM могут не достигать родителя вне
компонента, если не использовать composed: true. Для
пользовательских событий важно создавать их с правильными
настройками:
this.dispatchEvent(new CustomEvent('item-selected', {
detail: { item: this.item },
bubbles: true,
composed: true
}));
bubbles: true позволяет событию всплывать по дереву
DOM.composed: true делает событие доступным за пределами
Shadow DOM.Обработчик на внешнем компоненте сможет перехватить событие:
<my-element on-item-selected="_onItemSelected"></my-element>
Для элементов, создаваемых после инициализации компонента, делегирование упрощает добавление событий:
const container = this.shadowRoot.querySelector('#container');
container.addEventListener('click', (event) => {
if (event.target.matches('.dynamic-button')) {
console.log('Динамическая кнопка нажата:', event.target.textContent);
}
});
Метод matches позволяет проверять соответствие элемента
CSS-селектору, что делает делегирование гибким при работе с динамическим
контентом.
event.model в Polymer.Делегирование событий в Polymer является не только средством
оптимизации, но и фундаментальным подходом к созданию масштабируемых и
поддерживаемых веб-компонентов. Правильное использование всплытия
событий, event.model и composed обеспечивает
гибкость и безопасность взаимодействия между компонентами.