Кратко
Скопировано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, не поддерживается