В FAST Element слоты (<slot>) используются для
внедрения внешнего содержимого в компонент, обеспечивая высокую гибкость
и возможность создания переиспользуемых веб-компонентов. Часто требуется
не просто отображать содержимое слота, но и реагировать на его
динамические изменения. Для этого FAST Element предоставляет механизмы
отслеживания изменений слотов, позволяющие управлять состоянием
компонента в зависимости от содержимого.
Слот представляет собой область внутри компонента, куда может быть передан контент извне. Простейший пример:
import { FASTElement, html } from "@microsoft/fast-element";
const template = html<MyElement>`
<div>
<slot></slot>
</div>
`;
export class MyElement extends FASTElement {}
В этом примере любой контент, переданный внутрь
<my-element>, будет отображен внутри
<div>.
Важно понимать, что слот не является просто контейнером: он управляет распределением элементов внутри Shadow DOM и автоматически обновляет содержимое при изменениях в родительском DOM. Однако по умолчанию нет прямого способа отследить, когда содержимое слота изменилось, кроме использования стандартных событий браузера.
slotchangeHTML-слоты генерируют событие slotchange каждый раз,
когда их содержимое изменяется. FAST Element позволяет использовать это
событие для реактивного управления компонентом:
import { FASTElement, html } from "@microsoft/fast-element";
const template = html<MyElement>`
<div>
<slot @slotchange=${x => x.handleSlotChange()}></slot>
</div>
`;
export class MyElement extends FASTElement {
handleSlotChange() {
const slot = this.shadowRoot.querySelector('slot');
const assignedNodes = slot.assignedNodes({ flatten: true });
console.log('Содержимое слота изменилось:', assignedNodes);
}
}
Ключевые моменты:
@slotchange позволяет привязать метод обработчика к
событию слота.assignedNodes({ flatten: true }) возвращает все
элементы, включая вложенные слоты.assignedNodes или assignedElements —
основной способ получить текущее содержимое слота.Компонент может содержать несколько слотов с различными именами. Для каждого слота можно установить отдельный обработчик:
const template = html<MyElement>`
<div>
<slot name="header" @slotchange=${x => x.handleHeaderChange()}></slot>
<slot name="content" @slotchange=${x => x.handleContentChange()}></slot>
</div>
`;
export class MyElement extends FASTElement {
handleHeaderChange() {
const slot = this.shadowRoot.querySelector('slot[name="header"]');
const nodes = slot.assignedNodes({ flatten: true });
console.log('Header обновлен:', nodes);
}
handleContentChange() {
const slot = this.shadowRoot.querySelector('slot[name="content"]');
const nodes = slot.assignedNodes({ flatten: true });
console.log('Content обновлен:', nodes);
}
}
Это позволяет реагировать на изменения в конкретных областях компонента и гибко управлять его состоянием в зависимости от типа переданного контента.
В FAST Element можно интегрировать слоты с реактивными свойствами,
чтобы состояние компонента автоматически обновлялось при изменении
содержимого слота. Для этого используется метод
assignedNodes вместе с обновлением внутренних свойств:
import { FASTElement, html, observable } from "@microsoft/fast-element";
const template = html<MyElement>`
<div>
<slot @slotchange=${x => x.updateSlotNodes()}></slot>
<p>Количество элементов в слоте: ${x => x.slotCount}</p>
</div>
`;
export class MyElement extends FASTElement {
@observable slotCount = 0;
updateSlotNodes() {
const slot = this.shadowRoot.querySelector('slot');
this.slotCount = slot.assignedNodes({ flatten: true }).length;
}
}
Особенности подхода:
@observable делает свойство реактивным.slotCount автоматически вызывает
обновление DOM, что избавляет от необходимости вручную управлять
рендерингом.Событие slotchange информирует о добавлении или удалении
узлов, но не отслеживает изменения внутри самих элементов
слота. Для таких случаев можно использовать
MutationObserver:
export class MyElement extends FASTElement {
observer;
connectedCallback() {
super.connectedCallback();
const slot = this.shadowRoot.querySelector('slot');
const nodes = slot.assignedNodes({ flatten: true });
this.observer = new MutationObserver(mutations => {
console.log('Изменения внутри элементов слота:', mutations);
});
nodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
this.observer.observe(node, { childList: true, subtree: true, attributes: true });
}
});
slot.addEventListener('slotchange', () => {
this.observer.disconnect();
const updatedNodes = slot.assignedNodes({ flatten: true });
updatedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
this.observer.observe(node, { childList: true, subtree: true, attributes: true });
}
});
});
}
disconnectedCallback() {
super.disconnectedCallback();
this.observer.disconnect();
}
}
Этот подход позволяет отслеживать любые изменения внутри элементов, переданных в слот: добавление/удаление дочерних элементов, изменение атрибутов и структуры DOM.
slotchange для реакции на добавление или удаление
элементов.MutationObserver.Отслеживание изменений слотов в FAST Element является мощным инструментом для создания динамических, гибких веб-компонентов, позволяя реагировать на внешние изменения и поддерживать согласованное состояние интерфейса.