Перейти к содержимому

Веб-компоненты

Веб-компоненты — мощный инструмент в современной веб-разработке, позволяющий разработчикам создавать переиспользуемые и инкапсулированные HTML-элементы. В этом руководстве мы глубоко погрузимся в мир веб-компонентов, предоставив обширные примеры кода и подробные объяснения, чтобы помочь вам освоить этот важный аспект JavaScript.

Введение в веб-компоненты

Веб-компоненты — это набор API веб-платформы, которые позволяют создавать новые пользовательские, переиспользуемые и инкапсулированные HTML-теги для использования в веб-страницах и веб-приложениях. Основными технологиями, используемыми в веб-компонентах, являются Custom Elements, Shadow DOM и HTML Templates.

Пользовательские элементы

Пользовательские элементы определяют новые HTML-теги и их поведение. Эти элементы можно использовать так же, как и стандартные HTML-теги, но с пользовательской логикой и стилями.


html
<div>
  <script>
    class MyElement extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        this.shadowRoot.innerHTML = '<p>Hello, World!</p>';
      }
    }
    customElements.define('my-element', MyElement);
  </script>
  <my-element></my-element>
</div>

Этот фрагмент кода демонстрирует, как создать пользовательский HTML-элемент с именем my-element. Класс MyElement расширяет HTMLElement, прикрепляет shadow DOM для инкапсуляции его содержимого и вставляет простой абзац с текстом "Hello, World!".

Shadow DOM

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


html
<div>
  <script>
    class ShadowElement extends HTMLElement {
      constructor() {
        super();
        let shadow = this.attachShadow({ mode: 'open' });
        shadow.innerHTML = `
          <style>
            p { color: blue; }
          </style>
          <p>Shadow DOM content</p>
        `;
      }
    }
    customElements.define('shadow-element', ShadowElement);
  </script>
  <shadow-element></shadow-element>
</div>

В этом примере класс ShadowElement расширяет HTMLElement и прикрепляет shadow root к элементу. Параметр mode: 'open' указывает, что shadow DOM доступен через JavaScript. Когда mode установлен в 'open', shadow root можно получить с помощью свойства element.shadowRoot. Если mode установлен в 'closed', shadow root недоступен извне, что повышает инкапсуляцию и предотвращает прямое манипулирование shadow DOM внешними скриптами.

Внутри shadow DOM мы определяем некоторые стили и HTML-контент. Стили (в данном случае абзац с синим текстом) ограничены рамками shadow DOM, что гарантирует, что они не повлияют на другие элементы на странице. Такая инкапсуляция полезна для создания переиспользуемых компонентов с согласованным оформлением и поведением независимо от контекста их использования.

WARNING

Используйте локальные стили внутри Shadow DOM, чтобы предотвратить утечку стилей и гарантировать, что стили компонентов будут ограничены их рамками.

HTML Templates

HTML-шаблоны позволяют определять переиспользуемые фрагменты HTML, которые могут быть созданы во время выполнения.


html
<div>
  <template id="my-template">
    <style>
      p { color: red; }
    </style>
    <p>This is a template content</p>
  </template>
  <script>
    const template = document.getElementById('my-template').content;
    document.body.appendChild(template.cloneNode(true));
  </script>
</div>

Этот пример показывает, как использовать HTML-шаблоны. Тег <template> содержит HTML и стили, которые не отображаются сразу. Скрипт клонирует содержимое шаблона и добавляет его в тело документа, делая его видимым.

Создание вашего первого веб-компонента

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

Шаг 1: Определение компонента

Создайте новый класс, расширяющий HTMLElement.


html
<div>
  <script>
    class MyComponent extends HTMLElement {
      constructor() {
        super();
        const shadow = this.attachShadow({ mode: 'open' });
        shadow.innerHTML = 'Hello, World!'
      }
    }
    customElements.define('my-component', MyComponent);
  </script>
  <my-component></my-component>
</div>

Этот фрагмент закладывает основу для веб-компонента с именем my-component. Он определяет класс, расширяющий HTMLElement, и прикрепляет shadow DOM, подготавливая его к дальнейшей настройке.

Шаг 2: Добавление стилей и шаблонов

Используйте Shadow DOM для инкапсуляции стилей и шаблонов.


html
<div>
  <script>
    class MyStyledComponent extends HTMLElement {
      constructor() {
        super();
        let shadow = this.attachShadow({ mode: 'open' });
        shadow.innerHTML = `
          <style>
            p { font-size: 20px; color: green; }
          </style>
          <p>This is my styled component!</p>
        `;
      }
    }
    customElements.define('my-styled-component', MyStyledComponent);
  </script>
  <my-styled-component></my-styled-component>
</div>

Этот фрагмент улучшает my-styled-component, добавляя ограниченные стили внутри shadow DOM. Абзац внутри компонента оформлен зелёным цветом и увеличенным размером шрифта.

Шаг 3: Добавление интерактивности

Добавьте JavaScript, чтобы сделать ваш компонент интерактивным.


html
<div>
  <script>
    class InteractiveComponent extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        this.shadowRoot.innerHTML = `
          <style>
            p { font-size: 20px; }
          </style>
          <p>This is interactive!</p>
          <button>Click me</button>
        `;
        this.shadowRoot.querySelector('button').addEventListener('click', () => {
          this.shadowRoot.querySelector('p').textContent = 'You clicked!';
        });
      }
    }
    customElements.define('interactive-component', InteractiveComponent);
  </script>
  <interactive-component></interactive-component>
</div>

Этот пример показывает, как сделать веб-компонент интерактивным. InteractiveComponent включает кнопку, которая при нажатии изменяет текстовое содержимое абзаца внутри компонента.

Продвинутые техники веб-компонентов

Callbacks жизненного цикла

Пользовательские элементы имеют callbacks жизненного цикла, которые позволяют запускать код на определенных этапах жизни элемента.


html
<div>
  <script>
    class LifecycleComponent extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
      }
      connectedCallback() {
        this.shadowRoot.innerHTML = '<p>Element added to page.</p>';
      }
      disconnectedCallback() {
        console.log('Element removed from page.');
      }
    }
    customElements.define('lifecycle-component', LifecycleComponent);
  </script>
  <lifecycle-component></lifecycle-component>
</div>

Этот фрагмент демонстрирует использование callbacks жизненного цикла в веб-компонентах. LifecycleComponent обновляет свое содержимое при добавлении на страницу и выводит сообщение в консоль при удалении.

Обработка изменений атрибутов

Реагируйте на изменения атрибутов элемента, определив массив observedAttributes и реализовав метод attributeChangedCallback.


html
<div>
  <script>
    class AttributeComponent extends HTMLElement {
      static get observedAttributes() {
        return ['data-text'];
      }
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        this.shadowRoot.innerHTML = '<p></p>';
      }
      attributeChangedCallback(name, oldValue, newValue) {
        if (name === 'data-text') {
          this.shadowRoot.querySelector('p').textContent = newValue;
        }
      }
    }
    customElements.define('attribute-component', AttributeComponent);
  </script>
  <attribute-component data-text="Initial text"></attribute-component>
  <script>
    const element = document.querySelector('attribute-component');
    setTimeout(() => {
      element.setAttribute('data-text', 'Updated text');
    }, 2000);
  </script>
</div>

Этот пример показывает, как обрабатывать изменения атрибутов в веб-компоненте. AttributeComponent обновляет свое внутреннее содержимое в зависимости от изменений атрибута data-text.

Лучшие практики для веб-компонентов

Рационально используйте Shadow DOM

Инкапсулируйте стили и скрипты внутри Shadow DOM, чтобы предотвратить конфликты с другими элементами на странице.

Соблюдайте соглашения об именовании

Пользовательские элементы должны содержать дефис в названии, чтобы избежать конфликтов со стандартными HTML-элементами.

Делайте компоненты модульными

Создавайте небольшие, переиспользуемые компоненты, чтобы поддерживать масштабируемость и удобство сопровождения кодовой базы.

Избегайте глобальных стилей

Используйте локальные стили внутри Shadow DOM, чтобы предотвратить утечку стилей и гарантировать, что стили компонентов будут ограничены их рамками.

Документация и тестирование

Хорошо документируйте свои компоненты и пишите тесты, чтобы убедиться, что они работают как ожидается в разных браузерах и сценариях использования.

Заключение

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

Практика

Какое из следующих утверждений о Web Components верно?

Считаете ли это полезным?

Предпросмотр dual-run — сравните с маршрутами Symfony на продакшене.