Современный веб развивается бешеными темпами. Фреймворки появляются и исчезают, а стандарты остаются. Веб-компоненты — это набор технологий, который позволяет создавать собственные HTML-теги с инкапсулированной логикой и стилями. И всё это без единой строчки сторонних библиотек.
Что такое веб-компоненты и зачем они нужны
Представьте, что вы можете создать свой собственный тег <my-button> и использовать его на любой странице. Браузер поймёт его, отрисует кнопку с нужными стилями и поведением. Никаких React, Vue или Angular. Только стандартные возможности браузера.
Веб-компоненты решают главную проблему современной разработки — переиспользование кода. Вы пишете компонент один раз, а затем вставляете его где угодно. Стили не конфликтуют, потому что они инкапсулированы. JavaScript-логика изолирована. Это как LEGO: собрал деталь и используешь в разных конструкциях.
Основные технологии:
- Custom Elements — позволяют определять свои HTML-теги.
- Shadow DOM — изолирует стили и разметку внутри компонента.
- HTML Templates — шаблоны, которые не рендерятся до момента использования.
- ES Modules — импорт и экспорт кода между файлами.
Создаём первый компонент: кнопка с уведомлением
Начнём с простого. Сделаем кнопку, которая при клике показывает всплывающее сообщение. Но не обычную, а веб-компонент.
Сначала определим класс, который наследуется от HTMLElement. В конструкторе вызовем super() и создадим Shadow DOM.
class MyButton extends HTMLElement {
constructor() {
super();
// Создаём Shadow DOM
this.attachShadow({ mode: 'open' });
// Создаём кнопку
const button = document.createElement('button');
button.textContent = 'Нажми меня';
// Добавляем стили
const style = document.createElement('style');
style.textContent = `
button {
background: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #45a049;
}
`;
// Обработчик клика
button.addEventListener('click', () => {
alert('Привет из веб-компонента!');
});
// Собираем всё вместе
this.shadowRoot.append(style, button);
}
}
// Регистрируем элемент
customElements.define('my-button', MyButton);
Теперь в HTML можно просто написать <my-button></my-button>, и браузер отрисует стилизованную кнопку. Стили внутри Shadow DOM не влияют на остальную страницу, и наоборот.
mode: 'open' в attachShadow, если хотите иметь доступ к Shadow DOM извне через element.shadowRoot. Закрытый режим (mode: 'closed') делает shadow root недоступным, что усложняет отладку.
Жизненный цикл веб-компонента
У Custom Elements есть специальные методы, которые вызываются на разных этапах жизни. Их называют «реакциями» (reactions).
| Метод | Когда вызывается |
|---|---|
constructor() |
При создании экземпляра элемента |
connectedCallback() |
Когда элемент добавлен в DOM |
disconnectedCallback() |
Когда элемент удалён из DOM |
attributeChangedCallback() |
При изменении атрибута из списка observedAttributes |
adoptedCallback() |
При перемещении элемента в новый документ |
Чтобы отслеживать изменения атрибутов, нужно определить статический геттер observedAttributes.
class MyButton extends HTMLElement {
static get observedAttributes() {
return ['label', 'color'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'label') {
this.shadowRoot.querySelector('button').textContent = newValue;
}
if (name === 'color') {
this.shadowRoot.querySelector('button').style.backgroundColor = newValue;
}
}
}
Теперь можно менять текст и цвет кнопки через атрибуты: <my-button label="Отправить" color="#ff5722"></my-button>.
Использование шаблонов и слотов
Вместо создания элементов в JavaScript можно использовать тег <template>. Он не отображается на странице, но его содержимое доступно для клонирования.
<template id="my-button-template">
<style>
button {
background: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
}
</style>
<button><slot></slot></button>
</template>
Здесь <slot> — это место, куда будет вставлен контент из основного документа. Например:
<my-button>Нажми меня</my-button>
Текст «Нажми меня» попадёт внутрь кнопки. Это называется «слотами» (slots) и позволяет делать компоненты гибкими.
В JavaScript используем шаблон так:
class MyButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
const template = document.getElementById('my-button-template');
const clone = template.content.cloneNode(true);
this.shadowRoot.appendChild(clone);
}
}
customElements.define('my-button', MyButton);
<slot>Резервный текст</slot>. Оно отобразится, если в компонент не передали контент.
Стилизация и инкапсуляция
Одно из главных преимуществ Shadow DOM — изоляция стилей. Стили, определённые внутри компонента, не влияют на внешний мир, и наоборот. Но иногда нужно стилизовать сам хост-элемент (например, <my-button>). Для этого есть селектор :host.
const style = document.createElement('style');
style.textContent = `
:host {
display: inline-block;
margin: 5px;
}
button {
/* стили кнопки */
}
`;
Также можно использовать CSS-переменные для темизации:
style.textContent = `
button {
background: var(--button-bg, #4CAF50);
color: var(--button-color, white);
}
`;
Теперь снаружи можно задать --button-bg: red; и кнопка станет красной.
Практические советы и подводные камни
- Не злоупотребляйте Shadow DOM. Если компонент простой, может быть достаточно обычного класса.
- Следите за производительностью. Частые изменения в attributeChangedCallback могут вызвать лишние перерисовки.
- Используйте
customElements.whenDefined()для ожидания регистрации компонента. - Помните о полифилах. Старые браузеры (IE11) не поддерживают веб-компоненты, но для них есть полифилы.
Вот пример асинхронной загрузки компонента:
customElements.whenDefined('my-button').then(() => {
console.log('Компонент готов к использованию');
});
Ещё один важный момент: если вы используете сборщики (Webpack, Rollup), убедитесь, что они корректно обрабатывают веб-компоненты. Иногда требуется дополнительная настройка.
Заключение
Веб-компоненты — это мощный инструмент, который позволяет создавать переиспользуемые элементы без привязки к фреймворкам. Они основаны на стандартах, поддерживаются всеми современными браузерами и дают разработчикам гибкость и изоляцию. Начните с малого: сделайте простую кнопку или карточку. Постепенно вы оцените удобство и мощь этого подхода.
Помните: не нужно переписывать всё приложение на веб-компоненты. Используйте их там, где это действительно уместно. И тогда ваш код станет чище, а разработка — приятнее.



