Atomico — это современная библиотека для создания веб-компонентов на JavaScript с использованием реактивного подхода. Одной из ключевых возможностей является динамическое распределение контента, позволяющее гибко управлять отображением дочерних элементов и их структурой в DOM без переписывания логики компонентов.
Atomico строится на базе стандартов Web Components, что подразумевает использование Shadow DOM. Shadow DOM инкапсулирует внутреннюю структуру компонента, изолируя стили и предотвращая конфликт с внешними элементами.
Для динамического распределения контента применяются слоты
(<slot>), которые действуют как «места
подстановки» для элементов, переданных внутрь компонента. Слоты бывают
двух типов:
import { c, html } from "atomico";
function Card({ children }) {
return html`
<div class="card">
<header><slot name="header"></slot></header>
<section><slot></slot></section>
<footer><slot name="footer"></slot></footer>
</div>
`;
}
Card.props = {};
customElements.define("x-card", c(Card));
В этом примере элементы с атрибутом slot="header"
попадут в верхнюю часть карточки, а элементы без имени — в основной
слот.
Atomico позволяет управлять содержимым слотов на
лету, реагируя на изменения пропсов и состояния компонента. Для
этого применяется реактивный синтаксис и функция
children, возвращающая текущие дочерние
элементы:
import { c, html, useState } from "atomico";
function Tabs() {
const [active, setActive] = useState(0);
return html`
<div class="tabs">
<nav>
${["Tab 1", "Tab 2", "Tab 3"].map((name, index) => html`
<button class="${index === active ? "active" : ""}"
oncl ick=${() => setActive(index)}>
${name}
</button>`)}
</nav>
<section>
<slot name="tab-${active}"></slot>
</section>
</div>
`;
}
customElements.define("x-tabs", c(Tabs));
Здесь контент для каждой вкладки распределяется динамически, и слот
подставляется в зависимости от состояния active. Такой
подход позволяет строить компоненты с изменяемой структурой
DOM без повторного рендера всей иерархии.
Для более сложного распределения полезно использовать реактивные массивы с ключами. Atomico поддерживает реактивные списки, которые автоматически обновляют DOM при изменении элементов:
import { c, html, useState } from "atomico";
function List() {
const [items, setItems] = useState(["A", "B", "C"]);
return html`
<ul>
${items.map((item, i) => html`<li key=${i}>${item}</li>`)}
</ul>
<button oncl ick=${() => setItems([...items, "D"])}>Добавить</button>
`;
}
customElements.define("x-list", c(List));
Использование атрибута key критично для корректного
динамического распределения и обновления элементов,
поскольку Atomico сопоставляет существующие DOM-узлы с новыми данными и
минимизирует изменения в DOM.
Динамическое распределение также включает условное отображение элементов. Atomico поддерживает стандартный JavaScript-синтаксис для условных выражений в JSX-подобных шаблонах:
import { c, html, useState } from "atomico";
function ToggleContent() {
const [show, setShow] = useState(false);
return html`
<button oncl ick=${() => setShow(!show)}>Переключить</button>
${show && html`<div><slot></slot></div>`}
`;
}
customElements.define("x-toggle", c(ToggleContent));
Контент в слоте появляется или исчезает без удаления всего родительского узла, что улучшает производительность при больших и сложных компонентах.
Atomico поддерживает глубокую композицию слотов. Вложенные компоненты могут иметь свои слоты, а контент можно передавать через цепочку компонентов:
function Layout() {
return html`
<header><slot name="header"></slot></header>
<main><slot></slot></main>
<footer><slot name="footer"></slot></footer>
`;
}
function Page() {
return html`
<x-layout>
<h1 slot="header">Заголовок</h1>
<p>Основное содержание страницы</p>
<small slot="footer">Подвал</small>
</x-layout>
`;
}
При такой архитектуре динамическое распределение контента сохраняется независимо от вложенности, что делает компоненты Atomico максимально модульными.
Для более тонкой настройки распределения контента доступна
программная работа со слотами через API
children и assignedNodes():
const slot = shadowRoot.querySelector("slot[name='tab-0']");
const nodes = slot.assignedNodes({ flatten: true });
Метод assignedNodes возвращает массив элементов, которые
были переданы в конкретный слот, позволяя динамически модифицировать их
содержимое или порядок.
Динамическое распределение в Atomico позволяет строить гибкие, производительные и модульные компоненты, где контент может изменяться на лету, сохраняя структуру и логику приложения.