Представьте, что вы строите дом из готовых блоков. Каждый блок — это стена, окно или дверь. Вы просто берёте нужный блок и ставите на место. А если блок сломался — чините один, не трогая остальные. Примерно так работают веб-компоненты. Только вместо стен — кнопки, формы, виджеты. И всё это на чистом JavaScript, без React или Vue. Звучит круто? Поехали разбираться.

Что такое веб-компоненты и зачем они нужны PHP-разработчику

Веб-компоненты — это набор стандартов браузера, которые позволяют создавать свои собственные HTML-теги. Например, вы можете сделать тег <my-button>, который будет работать как обычная кнопка, но с вашим стилем и логикой. И никаких сторонних библиотек.

Для PHP-разработчика это особенно полезно. Почему? Потому что часто мы пишем бэкенд на PHP, а фронтенд — на коленке, с кучей скопированного JavaScript. Веб-компоненты помогают навести порядок: вы один раз создаёте компонент, а потом используете его в любом HTML-шаблоне, который генерирует PHP. Это как собрать свой собственный конструктор лего из готовых деталей.

Правило: Если вы используете один и тот же кусок HTML-кода в нескольких местах — это повод сделать из него веб-компонент. Экономит время и нервы.

Как устроен веб-компонент: три кита

Любой веб-компонент строится на трёх вещах:

  • Custom Elements — это самодельные HTML-теги. Вы определяете новый элемент, даёте ему имя и описываете поведение.
  • Shadow DOM — это изоляция стилей и разметки. Внутри компонента свои стили, которые не лезут наружу, и внешние стили не лезут внутрь. Как в консервной банке.
  • HTML Templates — это шаблоны, которые можно клонировать и вставлять в DOM. Удобно для повторяющихся структур.

Всё вместе это позволяет создавать компоненты, которые работают как встроенные теги браузера. Никаких конфликтов, никакой магии.

Создаём первый компонент: пользовательский элемент

Давайте напишем простой компонент — кастомную кнопку с иконкой. Для начала определим класс, который наследуется от HTMLElement:

class MyButton extends HTMLElement {
  constructor() {
    super();
    this.innerHTML = ``;
  }
}
customElements.define('my-button', MyButton);

Теперь в HTML можем использовать:

<my-button label='Отправить'></my-button>

Но это простейший случай. Без Shadow DOM стили могут переопределяться. Поэтому давайте добавим Shadow DOM.

Изолируем стили с Shadow DOM

Shadow DOM — это как если бы вы поставили компонент в отдельную комнату с непрозрачными стенами. Стили из внешнего мира туда не проникают.

class MyButton extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({mode: 'open'});
    shadow.innerHTML = `
      
      
    `;
  }
}
customElements.define('my-button', MyButton);

Теперь стили кнопки не сломаются, даже если на странице есть глобальные стили для button. Компонент полностью изолирован.

Лайфхак: Используйте атрибуты для настройки компонента. Например, label, color, size. Это делает компонент гибким, как конструктор.

Добавляем шаблоны и слоты

Шаблоны (<template>) позволяют хранить разметку, которая не отображается, пока её не активировать. Слоты — это места, куда можно вставлять контент извне. Например, сделаем карточку товара.

<template id='product-card'>
  
  
Название товара
0 руб.
class ProductCard extends HTMLElement {
  constructor() {
    super();
    const template = document.getElementById('product-card');
    const content = template.content.cloneNode(true);
    this.attachShadow({mode: 'open'}).appendChild(content);
  }
}
customElements.define('product-card', ProductCard);

Использование:

<product-card>
  Ноутбук
  50 000 руб.
  

Отличный ноутбук для работы.

</product-card>

Слоты позволяют вставлять любой HTML-контент внутрь компонента, сохраняя его структуру.

Жизненный цикл компонента: когда что происходит

У каждого компонента есть свои этапы жизни. Их можно отслеживать с помощью специальных методов:

МетодКогда вызывается
constructor()При создании элемента
connectedCallback()Когда элемент добавлен в DOM
disconnectedCallback()Когда элемент удалён из DOM
attributeChangedCallback()Когда изменяется атрибут (нужно указать observedAttributes)

Пример с отслеживанием атрибута:

class MyButton extends HTMLElement {
  static get observedAttributes() {
    return ['label'];
  }
  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'label') {
      this.shadowRoot.querySelector('button').textContent = newValue;
    }
  }
}

Это удобно, когда данные меняются динамически, например, после AJAX-запроса.

Взаимодействие с PHP: передаём данные из бэкенда

В PHP вы можете генерировать HTML с компонентами, передавая данные через атрибуты. Например:

$products = [
  ['title' => 'Ноутбук', 'price' => 50000],
  ['title' => 'Мышь', 'price' => 1500]
];
foreach ($products as $product) {
  echo "";
}

Но если данных много, лучше передавать их через data-* атрибуты или JSON в скрипте. Например:

<script>
  const data = ;
  data.forEach(item => {
    const card = document.createElement('product-card');
    card.setAttribute('label', item.title);
    card.setAttribute('price', item.price);
    document.body.appendChild(card);
  });
</script>

Так вы отделяете данные от представления, и компоненты становятся чистыми.

Правило: Не смешивайте PHP и JavaScript в одном файле. Используйте JSON как мост между бэкендом и фронтендом. Это упрощает отладку и поддержку.

Что в итоге: резюме

Веб-компоненты на нативном JavaScript — это мощный инструмент для создания переиспользуемых элементов интерфейса. Они работают в любом современном браузере, не требуют фреймворков и легко интегрируются с PHP. Вы получаете изоляцию стилей, модульность и чистый код. Начните с малого: замените повторяющиеся куски HTML на кастомные элементы. Со временем соберёте свою библиотеку компонентов, которая сэкономит часы разработки.

А если захотите углубиться — изучите slot, template и жизненные циклы. Это как перейти от велосипеда к автомобилю: быстрее, удобнее, но требует практики.

Студия WNDER