Haunted — это библиотека для построения компонентов на основе веб-компонентов с использованием функций и реактивного состояния, вдохновлённая подходом React Hooks. Одной из ключевых возможностей, позволяющих создавать гибкие и переиспользуемые компоненты, являются именованные слоты. Они позволяют организовать структуру компонента так, чтобы потребители могли вставлять контент в определённые области, сохраняя при этом контроль над структурой и стилями.
В веб-компонентах существует концепция слотов, которая позволяет вставлять произвольный HTML-контент внутрь компонента. По умолчанию используется слот без имени, куда попадает любой контент, не привязанный к конкретному слоту:
import { component, html } from 'haunted';
function Card({ title, children }) {
return html`
<div class="card">
<h2>${title}</h2>
<div class="content">
<slot></slot>
</div>
</div>
`;
}
customElements.define('my-card', component(Card));
Использование:
<my-card title="Пример">
<p>Это основной контент карточки.</p>
</my-card>
В этом случае <p> автоматически попадёт в
дефолтный слот.
Именованные слоты позволяют разделить область компонента на несколько
логических частей, куда можно вставлять отдельные блоки контента. Для
создания именованного слота используется атрибут name:
function Modal() {
return html`
<div class="modal">
<header>
<slot name="header"></slot>
</header>
<section>
<slot name="body"></slot>
</section>
<footer>
<slot name="footer"></slot>
</footer>
</div>
`;
}
customElements.define('my-modal', component(Modal));
Использование:
<my-modal>
<h1 slot="header">Заголовок модального окна</h1>
<p slot="body">Основной текст модального окна.</p>
<button slot="footer">Закрыть</button>
</my-modal>
В этом примере каждый элемент попадает строго в свой слот: заголовок
в <header>, тело в <section>,
кнопка — в <footer>.
Haunted позволяет использовать реактивное состояние через хук
useState. Именованные слоты совместимы с реактивными
изменениями:
import { useState } from 'haunted';
function Alert() {
const [message, setMessage] = useState('Начальное сообщение');
return html`
<div class="alert">
<slot name="icon"></slot>
<span>${message}</span>
<button @click=${() => setMessage('Сообщение обновлено')}>Обновить</button>
</div>
`;
}
customElements.define('my-alert', component(Alert));
При этом <slot name="icon"> можно заполнять любым
содержимым извне, а реактивный <span> обновляется
автоматически при изменении состояния.
Именованные слоты могут содержать контент по умолчанию, который будет отображаться, если соответствующий слот не заполнен:
function CardWithDefaultSlot() {
return html`
<div class="card">
<header>
<slot name="header">Заголовок по умолчанию</slot>
</header>
<main>
<slot name="body">Содержимое по умолчанию</slot>
</main>
</div>
`;
}
customElements.define('my-card-default', component(CardWithDefaultSlot));
Использование без слотов:
<my-card-default></my-card-default>
Отобразится стандартный заголовок и тело. Если передать слоты, они заменят дефолтный контент.
Слоты можно стилизовать через CSS-псевдокласс
::slotted:
card-with-default ::slotted([slot="header"]) {
font-weight: bold;
color: darkblue;
}
card-with-default ::slotted([slot="body"]) {
font-style: italic;
}
Особенности: ::slotted позволяет стилизовать только
верхний уровень элементов, вложенные теги не затрагиваются.
В сложных компонентах удобно комбинировать слоты:
function Layout() {
return html`
<nav>
<slot name="nav">Меню по умолчанию</slot>
</nav>
<main>
<slot></slot>
</main>
<aside>
<slot name="aside">Боковая панель по умолчанию</slot>
</aside>
`;
}
customElements.define('my-layout', component(Layout));
Использование:
<my-layout>
<p>Главный контент</p>
<div slot="nav">Пользовательское меню</div>
</my-layout>
В этом примере <p> попадает в дефолтный слот
<main>, <div> заменяет дефолтное
меню.
Haunted позволяет динамически формировать слоты на основе данных:
function TabView({ tabs }) {
return html`
<div class="tabs">
${tabs.map(
(tab) => html`<slot name="${tab.name}">${tab.defaultContent}</slot>`
)}
</div>
`;
}
customElements.define('my-tab-view', component(TabView));
Такой подход позволяет создавать компоненты с переменным числом областей, каждая из которых может иметь уникальное имя и дефолтный контент.
Именованные слоты в Haunted обеспечивают гибкость и контроль структуры компонентов, позволяя создавать сложные интерфейсы с реактивными данными, стилями и динамическими областями для контента. Они позволяют строить компоненты, которые легко расширяются и переиспользуются без изменения внутренней логики.