Lit — это современный фреймворк для создания веб-компонентов на основе стандартов Web Components. Эффективная передача данных между компонентами является одной из ключевых задач при построении сложных интерфейсов. В Lit это реализуется через свойства (properties), атрибуты (attributes), события (events) и контекст (context).
В Lit компонент может иметь свойства, которые
автоматически синхронизируются с его шаблоном. Объявление свойства
осуществляется с помощью декоратора @property:
import { LitElement, html } from 'lit';
import { property } from 'lit/decorators.js';
class UserCard extends LitElement {
@property({ type: String }) name = '';
@property({ type: Number }) age = 0;
render() {
return html`<p>${this.name}, ${this.age} лет</p>`;
}
}
customElements.define('user-card', UserCard);
Свойства могут быть связаны с атрибутами HTML, что позволяет передавать данные через разметку:
<user-card name="Иван" age="30"></user-card>
Важно: все свойства, синхронизированные с
атрибутами, автоматически конвертируются в указанный тип
(String, Number, Boolean,
Array, Object) через механизм Lit.
Lit обеспечивает реактивность компонентов. Любое изменение свойства вызывает обновление шаблона. Для передачи данных от родителя к дочернему компоненту используется простая установка значения свойства:
const userCard = document.querySelector('user-card');
userCard.name = 'Мария';
userCard.age = 25;
После этого render перерисует компонент, отражая новые
данные.
Для передачи данных от дочернего компонента к родительскому используется механизм кастомных событий:
class CounterButton extends LitElement {
@property({ type: Number }) count = 0;
increment() {
this.count++;
this.dispatchEvent(new CustomEvent('count-changed', {
detail: { count: this.count },
bubbles: true,
composed: true
}));
}
render() {
return html`<button @click=${this.increment}>${this.count}</button>`;
}
}
customElements.define('counter-button', CounterButton);
Родительский компонент может слушать событие и обновлять свои данные:
<counter-button id="counter"></counter-button>
<script>
const counter = document.getElementById('counter');
counter.addEventListener('count-changed', (e) => {
console.log('Новый счет:', e.detail.count);
});
</script>
Ключевые моменты:
bubbles: true позволяет событию всплывать вверх по
DOM.composed: true позволяет событию проходить через Shadow
DOM границы.Слоты позволяют компонентам принимать вложенный контент:
class CardComponent extends LitElement {
render() {
return html`
<div class="card">
<slot></slot>
</div>
`;
}
}
customElements.define('card-component', CardComponent);
Вложенный контент передается через разметку:
<card-component>
<p>Контент внутри карточки</p>
</card-component>
Слоты хорошо подходят для передачи не данных, а структурного контента.
Для сложных приложений с глубокой иерархией компонентов использование
контекста упрощает передачу данных без явной проброски
через каждый компонент. В Lit применяются специальные API, такие как
@contextProvider и @contextConsumer (из
lit-context или аналогичных библиотек).
Пример предоставления и потребления контекста:
import { contextProvider, contextConsumer } from '@lit-labs/context';
import { createContext } from '@lit-labs/context';
const ThemeContext = createContext('theme');
class ThemeProvider extends LitElement {
@contextProvider({ context: ThemeContext })
theme = 'dark';
render() {
return html`<slot></slot>`;
}
}
class ThemedButton extends LitElement {
@contextConsumer({ context: ThemeContext })
theme;
render() {
return html`<button class=${this.theme}>Кнопка</button>`;
}
}
Контекст позволяет избежать “проброса” данных через каждый уровень DOM, сохраняя реактивность.
Каждый метод имеет свои преимущества и применим в зависимости от задачи: реактивные свойства подходят для прямого связывания данных, события — для уведомления родителей, слоты — для контента, контекст — для глобальных настроек и состояний.
Эта система передачи данных делает Lit мощным инструментом для построения сложных, реактивных веб-компонентов с чистой и понятной архитектурой.