Lit — это современный веб-фреймворк для создания легковесных и
высокопроизводительных пользовательских интерфейсов. Основой любой
архитектуры на Lit является веб-компонент, реализуемый
через класс, наследующийся от LitElement. Ключевое отличие
от традиционного подхода заключается в декларативном описании
шаблонов и реактивного состояния.
import { LitElement, html, css } from 'lit';
class MyComponent extends LitElement {
static properties = {
count: { type: Number }
};
static styles = css`
p { color: blue; font-size: 16px; }
`;
constructor() {
super();
this.count = 0;
}
render() {
return html`<p>Счётчик: ${this.count}</p>`;
}
}
customElements.define('my-component', MyComponent);
Ключевые моменты:
properties — реактивные свойства компонента, изменения
которых автоматически обновляют DOM.render() — метод, возвращающий шаблон с использованием
tagged template literals.css — встроенная поддержка стилей на уровне
компонента.Reactivity в Lit построена на отслеживании изменений свойств. Любое изменение реактивного свойства запускает повторный рендер компонента, при этом обновляются только те части DOM, которые реально изменились.
this.count += 1; // вызовет обновление шаблона
Для сложных структур данных используются сеттеры и методы обновления, чтобы корректно инициировать ререндер.
set data(newData) {
this._data = newData;
this.requestUpdate('data', this._data);
}
get data() { return this._data; }
Lit поддерживает Shadow DOM, что позволяет
изолировать стили компонента от глобальных CSS. Стили можно задавать как
через статический styles, так и динамически:
static styles = css`
:host { display: block; padding: 10px; background: #f0f0f0; }
.highlight { color: red; }
`;
:host — селектор, применяемый к корневому элементу
компонента.
Для создания гибких интерфейсов используется механизм слотов, позволяющий вставлять внешние элементы внутрь компонента.
render() {
return html`
<div>
<slot name="header"></slot>
<p>Основной контент</p>
<slot name="footer"></slot>
</div>
`;
}
slot — точка вставки внешнего контента.name позволяет создавать именованные слоты для разных
частей компонента.События внутри компонентов создаются с использованием
CustomEvent и могут быть перехвачены внешними
слушателями.
this.dispatchEvent(new CustomEvent('count-changed', {
detail: { value: this.count },
bubbles: true,
composed: true
}));
bubbles и composed — критически важные для
того, чтобы событие могло проходить через Shadow DOM.addEventListener.Lit идеально подходит для Progressive Web App паттернов благодаря модульности и легковесности. Компоненты можно загружать лениво, используя динамический импорт:
const module = await import('./my-component.js');
Для SPA на Lit часто используется библиотека маршрутизации
(@vaadin/router), где каждая страница реализуется как
компонент:
import { Router } from '@vaadin/router';
const outlet = document.getElementById('outlet');
const router = new Router(outlet);
router.setRoutes([
{ path: '/', component: 'home-page' },
{ path: '/about', component: 'about-page' },
]);
Каждая страница — это веб-компонент с собственной логикой и шаблоном, что упрощает lazy loading и code splitting.
Lit-компоненты отлично сочетаются с сервис-воркерами, кешированием и push-уведомлениями. Например, для offline-режима:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
requestUpdate() позволяет динамически
обновлять данные после восстановления соединения.Lit совместим с большинством современных библиотек UI и state management. Использование сторонних решений, таких как Redux, Zustand или RxJS, позволяет управлять состоянием на глобальном уровне, не нарушая реактивную архитектуру компонентов:
import { connect } from 'pwa-helpers';
import { store } from './store.js';
class MyComponent extends connect(store)(LitElement) {
// реактивные свойства будут синхронизироваться с глобальным state
}
Для плавного UX применяются CSS-анимации и Web Animations API. Поскольку Lit поддерживает обновление только изменённых частей DOM, анимации остаются независимыми и не перегружают рендер.
this.shadowRoot.querySelector('p').animate([
{ opacity: 0 }, { opacity: 1 }
], { duration: 500 });
Такой подход обеспечивает масштабируемость, повторное использование компонентов и совместимость с современными PWA-паттернами, сохраняя лёгкость и производительность приложения.