<MyRusakov.ru />

Разработчик игр на Unreal Engine

Разработчик игр на Unreal Engine

Этот комплект с нуля всего за 7 месяцев сделает Вас Unreal-разработчиком. И при этом учиться достаточно 1 час в день.

Начнёте Вы с основ программирования, постепенно перейдя к C++. Затем очень подробно изучите Unreal Engine, и после научитесь программировать на C++ в Unreal Engine. В конце создадите крупный проект на C++ в Unreal Engine для своего портфолио.

Комплект содержит:

- 416 видеоуроков

- 95 часов видео

- 1024 задания для закрепления материала из уроков

- 3 финальных тестирования

- 4 сертификата

- 12 Бонусных курсов

Подробнее
Подписка

Подпишитесь на мой канал на YouTube, где я регулярно публикую новые видео.

YouTube Подписаться

Подписавшись по E-mail, Вы будете получать уведомления о новых статьях.

Подписка Подписаться

Добавляйтесь ко мне в друзья ВКонтакте! Отзывы о сайте и обо мне оставляйте в моей группе.

Мой аккаунт Мой аккаунт Моя группа
Опрос

Какая тема Вас интересует больше?

Web Components (Custom Elements и Shadow DOM): практическое руководство для начинающих

Web Components (Custom Elements и Shadow DOM): практическое руководство для начинающих

Если вы хотите делать аккуратные и переиспользуемые интерфейсные блоки без React/Vue, Web Components — то, что нужно. В этом руководстве мы шаг за шагом создадим несколько компонентов, разберём Custom Elements, Shadow DOM, шаблоны, слоты, работу с атрибутами и событиями. Всё на чистом HTML5+JS.

Что такое Web Components

  • Custom Elements — собственные HTML-теги, например <user-card>.
  • Shadow DOM — инкапсуляция разметки и стилей внутри компонента.
  • HTML Templates & Slots — шаблоны для разметки и точки вставки пользовательского контента.

Поддержка: все современные браузеры. Полифилы пригодятся только для очень старых версий.

Быстрый старт: минимальный Custom Element

Создадим простой элемент, который приветствует по имени.

class HelloWorld extends HTMLElement {
  connectedCallback() {
    const name = this.getAttribute('name') || 'мир';
    this.textContent = `Привет, ${name}!`;
  }
}
customElements.define('hello-world', HelloWorld);
<hello-world name='Аня'></hello-world>

Важно: имя кастомного элемента обязательно содержит дефис (например, hello-world), иначе браузер отклонит регистрацию.

Shadow DOM и шаблон: изолируем стили

Теперь сделаем полноценный компонент карточки пользователя с закрытой разметкой и стилями.

<template id='user-card-tpl'>
  <style>
    :host {
      display: block;
      font: 14px/1.4 system-ui, sans-serif;
      border: 1px solid #e5e7eb;
      border-radius: 8px;
      padding: 12px;
      background: #fff;
    }
    .name { font-weight: 600; }
    .meta { color: #6b7280; }
    ::slotted(img) { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; }
  </style>
  <div class='row'>
    <slot name='avatar'></slot>
    <div class='info'>
      <div class='name' part='name'><slot name='name'>Без имени</slot></div>
      <div class='meta'><slot name='meta'>Пользователь</slot></div>
    </div>
  </div>
</template>

class UserCard extends HTMLElement {
  constructor() {
    super();
    const tpl = document.getElementById('user-card-tpl');
    const root = this.attachShadow({ mode: 'open' });
    root.appendChild(tpl.content.cloneNode(true));
  }
}
customElements.define('user-card', UserCard);
<user-card>
  <img slot='avatar' src='avatar.jpg' alt='Аватар'>
  <span slot='name'>Иван Петров</span>
  <span slot='meta'>Frontend разработчик</span>
</user-card>

Здесь мы используем слоты: внешний HTML передаёт картинку и тексты внутрь компонента, а стили остаются инкапсулированными в Shadow DOM.

Атрибуты, свойства и жизненный цикл

Добавим реакцию на изменение атрибутов с помощью observedAttributes и attributeChangedCallback.

class BadgeDot extends HTMLElement {
  static get observedAttributes() { return ['color', 'size']; }

  constructor() {
    super();
    this._root = this.attachShadow({ mode: 'open' });
    this._root.innerHTML = `
      <style>
        :host{display:inline-block;vertical-align:middle}
        .dot{border-radius:50%;display:inline-block}
      </style>
      <span class='dot' part='dot'></span>`;
    this._dot = this._root.querySelector('.dot');
    this._render();
  }

  attributeChangedCallback() { this._render(); }

  _render() {
    const size = Number(this.getAttribute('size') || 8);
    const color = this.getAttribute('color') || '#10b981';
    this._dot.style.width = size + 'px';
    this._dot.style.height = size + 'px';
    this._dot.style.background = color;
  }
}
customElements.define('badge-dot', BadgeDot);
Статус: <badge-dot color='#ef4444' size='10'></badge-dot>

Совет: синхронизируйте атрибуты и JS-свойства. Например, сделайте get/set для удобства: element.size = 12;.

Стилизация компонентов снаружи

Глобальные стили внутрь Shadow DOM не проникают. Чтобы разрешить внешнюю стилизацию отдельных частей, используйте механизмы parts/::part и псевдоклассы :host, ::slotted.

/* внутри компонента уже есть part='name' */
/* снаружи страницы: */
user-card::part(name){ color:#2563eb; }

/* состояние компонента через атрибуты и :host */
/* внутри shadow CSS */
:host([variant='warning']){ border-color:#f59e0b; background:#fffbeb; }

Коммуникация: события из компонента

Компонент часто должен сообщать о действиях наружу. Для этого диспатчим кастомные события.

class ToggleSwitch extends HTMLElement {
  constructor(){
    super();
    const root = this.attachShadow({mode:'open'});
    root.innerHTML = `
      <style>
        :host{display:inline-block;cursor:pointer;user-select:none}
        .track{width:42px;height:24px;background:#e5e7eb;border-radius:12px;position:relative;transition:.2s}
        .thumb{width:20px;height:20px;background:#fff;border-radius:50%;position:absolute;top:2px;left:2px;transition:.2s;box-shadow:0 1px 3px rgba(0,0,0,.2)}
        :host([checked]) .track{background:#22c55e}
        :host([checked]) .thumb{left:20px}
      </style>
      <div class='track' role='switch' aria-checked='false' tabindex='0'>
        <div class='thumb'></div>
      </div>`;
    this._track = root.querySelector('.track');
    this.addEventListener('click', () => this.toggle());
    this.addEventListener('keydown', e => { if(e.key===' '||e.key==='Enter'){ e.preventDefault(); this.toggle(); }});
  }
  toggle(){
    const next = !this.hasAttribute('checked');
    this.toggleAttribute('checked', next);
    this._track.setAttribute('aria-checked', String(next));
    this.dispatchEvent(new CustomEvent('change', { detail:{ checked: next }, bubbles:true, composed:true }));
  }
}
customElements.define('toggle-switch', ToggleSwitch);
<toggle-switch id='t1'></toggle-switch>
<script>
  document.getElementById('t1').addEventListener('change', e => {
    console.log('Состояние:', e.detail.checked);
  });
</script>

Флаги bubbles:true и composed:true позволяют событию выйти из Shadow DOM и быть пойманным в документе.

Доступность и SEO

  • Добавляйте роли и aria-атрибуты внутри Shadow DOM (пример выше: role='switch').
  • Убедитесь, что компонент фокусируемый и управляемый с клавиатуры.
  • Текстовый контент в слотах индексируется как обычный HTML.

Типичные ошибки новичков

  • Отсутствует дефис в названии элемента — регистрация не пройдёт.
  • Ожидание, что глобальный CSS применится к Shadow DOM — нет, используйте ::part, :host, ::slotted.
  • Избыточные перерисовки в attributeChangedCallback — кэшируйте ссылки на узлы и обновляйте точечно.
  • Манипуляции innerHTML с непроверенными данными — риск XSS. Шаблоны и безопасные вставки предпочтительнее.

Производительность: коротко по делу

  • Клонируйте готовый <template> вместо конкатенации строк.
  • Повторно используйте ссылки на элементы (this._node) и избегайте лишних querySelector.
  • Для больших библиотек стилей рассмотрите adoptedStyleSheets (Constructable Stylesheets).

Когда Web Components особенно уместны

  • UI-библиотека, независимая от фреймворков.
  • Виджеты для вставки на сторонние сайты (инкапсуляция стилей спасает).
  • Долгоживущие проекты, где важна стабильность нативного стека.

Хотите уверенно верстать интерфейсы, понимать каскад, шрифты, сетки и собирать аккуратные компоненты? Самое время прокачаться: загляните в практический курс по вёрстке «Вёрстка сайта с нуля 2.0» — он отлично дополняет тему Web Components и ускорит прогресс.

Итоги

Мы разобрали ключевые части Web Components: Custom Elements, Shadow DOM, шаблоны и слоты; подключили стили, атрибуты, события и доступность. Этого достаточно, чтобы начать собирать собственную библиотеку нативных UI-элементов без зависимостей. Дальше можно углубляться в ::part/::theme, adoptedStyleSheets и form-associated элементы. Удачной разработки!

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (https://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: https://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: https://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как создать свой сайт

  2. Текстовая ссылка:

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.