Кратко
Скопированоwindow
— это глобальный объект, который предоставляет методы для создания, регистрации и получения пользовательских HTML-элементов (Web Components).
Пример
Скопировано<my-greeting></my-greeting>
<my-greeting></my-greeting>
class MyGreeting extends HTMLElement { connectedCallback() { this.innerHTML = `<p>👋 Привет из кастомного элемента!</p>`; }}customElements.define('my-greeting', MyGreeting);
class MyGreeting extends HTMLElement { connectedCallback() { this.innerHTML = `<p>👋 Привет из кастомного элемента!</p>`; } } customElements.define('my-greeting', MyGreeting);
Как пишется
СкопированоОбъект custom
— это свойство window
. Он предоставляет следующие методы:
.define
— регистрирует новый пользовательский элемент.( name , constructor , options ) .get
— возвращает конструктор уже зарегистрированного элемента.( name ) .when
— возвращает промис, который выполнится, когда элемент будет определён.Defined ( name ) .upgrade
— вручную активирует пользовательские элементы внутри указанного( root ) root
..get
— возвращает имя пользовательского элемента по его конструктору, если он был зарегистрирован. Если конструктор не был зарегистрирован, возвращаетName ( constructor ) undefined
.
Рассмотрим подробнее каждый метод:
.define(name, constructor, options)
СкопированоРегистрирует новый пользовательский элемент.
-
name
— строка, имя нового тега (обязательно). Имя должно содержать хотя бы один дефис (-
), чтобы не пересекаться с существующими HTML-тегами, например,my
. Если имя не содержит дефиса, будет выброшено исключение. Если попытаться зарегистрировать элемент с именем, которое уже занято другим веб-компонентом, также возникнет ошибка. Подробнее о правилах именования пользовательских элементов можно прочитать в спецификации Custom Elements.- element -
constructor
— класс, который наследуется отHTML
или другого встроенного элемента (built-in HTML elements), например,Element HTML
. Встроенные элементы — это стандартные элементы HTML, такие какButton Element <button>
,<input>
,<ul>
и т.д. Наследование от них позволяет расширять их поведение. Например, если вы хотите создать свою кнопку на основе стандартной, используйтеclass
.My Button extends H T M L Button Element -
options
— объект с дополнительными настройками (необязательно). Обычно используется для расширения встроенных элементов через свойствоextends
, например:{ extends
для создания кастомной кнопки на основе стандартной.: 'button' }
В чём разница между наследованием от HTMLElement
и, например, HTMLButtonElement
?
Если вы наследуетесь от HTML
, вы создаёте полностью новый элемент с нуля. Если от встроенного элемента (например, HTML
), то ваш компонент будет вести себя как стандартная кнопка, но с дополнительной логикой или стилями.
.get(name)
СкопированоВозвращает конструктор уже зарегистрированного элемента по имени. Если элемент не зарегистрирован — вернёт undefined
.
.whenDefined(name)
СкопированоВозвращает промис, который выполнится, когда элемент с указанным именем будет определён. Удобно использовать, если элемент может быть зарегистрирован позже.
.upgrade(root)
СкопированоВручную активирует пользовательские элементы внутри указанного корня (например, если элементы были добавлены в DOM до регистрации).
.getName(constructor)
СкопированоЭтот метод позволяет узнать, под каким именем был зарегистрирован пользовательский элемент по его конструктору (классу). Если переданный конструктор был зарегистрирован через custom
, метод вернёт строку с именем тега (например, 'my
). Если конструктор не был зарегистрирован как пользовательский элемент, метод вернёт undefined
.
Это удобно, если у вас есть класс компонента и вы хотите узнать, зарегистрирован ли он в реестре кастомных элементов, и если да — под каким именем.
Как понять
СкопированоИногда стандартные HTML-элементы не подходят для ваших задач. Например:
- Нужен сложный компонент с собственной логикой (календарь, слайдер, модальное окно)
- Хочется переиспользовать один и тот же блок кода на разных страницах
- Нужно инкапсулировать стили и поведение, чтобы они не конфликтовали с остальной страницей
В таких случаях вы можете создать собственный HTML-тег с помощью custom
. Это позволяет:
- разделять код на логические блоки;
- повторно использовать компонент на странице;
- инкапсулировать логику и стили (если используется Shadow DOM).
Так же при создании кастомных элементом, важно знать несколько важных моментов:
- Регистрация до использования: Рекомендуется регистрировать все пользовательские элементы с помощью
custom
до того, как они появятся в DOM. Это можно сделать, подключив скрипт с регистрацией вElements . define <head>
или в начале вашего основного JavaScript-файла, до вставки соответствующих тегов на страницу. Если элемент окажется в DOM до регистрации, браузер создаст вместо негоHTML
, и только после регистрации выполнит «апгрейд» до нужного класса и вызовет, например,Unknown Element connected
.Callback
// До апгрейда браузером — элемент представлен как HTMLUnknownElement,// после регистрации и апгрейда — становится экземпляром вашего классаdocument.body.innerHTML = '<my-element></my-element>';customElements.define('my-element', class extends HTMLElement { connectedCallback() { this.textContent = 'Привет!'; }});
// До апгрейда браузером — элемент представлен как HTMLUnknownElement, // после регистрации и апгрейда — становится экземпляром вашего класса document.body.innerHTML = '<my-element></my-element>'; customElements.define('my-element', class extends HTMLElement { connectedCallback() { this.textContent = 'Привет!'; } });
// Сразу становится экземпляром вашего классаcustomElements.define('my-element', class extends HTMLElement { connectedCallback() { this.textContent = 'Привет!'; }});document.body.innerHTML = '<my-element></my-element>';
// Сразу становится экземпляром вашего класса customElements.define('my-element', class extends HTMLElement { connectedCallback() { this.textContent = 'Привет!'; } }); document.body.innerHTML = '<my-element></my-element>';
- Реакция на регистрацию с помощью
when
: Если элемент уже есть в DOM, но ещё не зарегистрирован, можно использоватьDefined ( ) when
, чтобы выполнить какие-то действия сразу после его регистрации. Например, это удобно, если вы хотите заменить временный плейсхолдер на содержимое кастомного элемента:Defined ( )
<!-- HTML с кастомным элементом --><custom-element> <h1 slot="title">Кастомный элемент</h1> <p slot="content">Контент появился после инициализации</p></custom-element>
<!-- HTML с кастомным элементом --> <custom-element> <h1 slot="title">Кастомный элемент</h1> <p slot="content">Контент появился после инициализации</p> </custom-element>
// Отслеживаем момент определения элементаcustomElements.whenDefined('custom-element').then(() => { console.log('Элемент custom-element определен!'); const element = document.querySelector('custom-element'); element.setAttribute('data-defined', 'true');});// Регистрируем элементclass CustomElement extends HTMLElement { constructor() { super() const shadow = this.attachShadow({ mode: "open" }) const template = document.getElementById("custom-element-template") shadow.appendChild(template.content.cloneNode(true)) }}customElements.define("custom-element", CustomElement);
// Отслеживаем момент определения элемента customElements.whenDefined('custom-element').then(() => { console.log('Элемент custom-element определен!'); const element = document.querySelector('custom-element'); element.setAttribute('data-defined', 'true'); }); // Регистрируем элемент class CustomElement extends HTMLElement { constructor() { super() const shadow = this.attachShadow({ mode: "open" }) const template = document.getElementById("custom-element-template") shadow.appendChild(template.content.cloneNode(true)) } } customElements.define("custom-element", CustomElement);
- Именование: Названия пользовательских элементов обязательно должны содержать дефис (например,
my
,- card user
), чтобы избежать конфликтов с будущими встроенными HTML-элементами.- list
Подсказки
Скопировано💡 Метод upgrade
полезен для активации кастомных элементов в динамически добавленном контенте.
💡 Используйте custom
для проверки, зарегистрирован ли элемент.
💡 Можно расширять не только HTML
, но и, например, HTML
, указав третий параметр { extends
, но тогда <button is
(не <my
) — требуется атрибут is
.
- Chrome 67, поддерживается
- Edge 79, поддерживается
- Firefox 63, поддерживается
- Safari, не поддерживается