Приложения становятся все сложнее, и нам нужен способ разделять код на управляемые фрагменты. Веб-компоненты подойдут для создания компонентов, которые можно неоднократно использовать.
Веб-компоненты также изолированы от других участков кода, следовательно, их сложно изменить из других разделов и создать конфликтующий код.
В этой статье мы рассмотрим разные части веб-компонентов и способы их создания.
Части веб-компонентов
Веб-компоненты состоят из 3 основных частей. Вместе они инкапсулируют функциональность, которую можно повторно использовать в любое время, не опасаясь конфликтов кода.
- Пользовательский элемент — набор JavaScript API, позволяющий задавать пользовательские элементы, которые можно использовать в пользовательском интерфейсе, и их поведение.
- Теневой DOM — набор JavaScript API для подключения инкапсулированного дерева теневого DOM элемента. Он отображается отдельно от основного DOM документа, что сохраняет приватность функций элемента, следовательно, он может выполняться без конфликтов с другими частями документа.
- HTML шаблоны— элементы
template
илиslot
позволяют нам писать шаблоны разметки, которые не отображаются на странице. Их можно многократно использовать как основу структуры пользовательских элементов.
Создание веб-компонентов
Чтобы создать веб-компонент, нужно сделать следующее:
- Создать класс или функцию, чтобы определить функциональность веб-компонента.
- Зарегистрировать новый пользовательский элемент, используя метод
CustomElementRegistry.define()
, передающий имя элемента, который нужно определить, класс или функцию с заданной функциональностью, и, если необходимо, наследование элемента. - Прикрепить теневой DOM к пользовательскому элементу, используя метод
Element.attachSHadow()
. Добавить дочерние элементы, слушатели событий и т.д. в теневой DOM, используя методы обычного DOM. - Задать шаблоны HTML, используя тэги
template
иslot
. Используем стандартные методы DOM для клонирования шаблона и подключения его к нашему теневому DOM. - Использовать пользовательский элемент на странице как и любой другой обычный элемент HTML.
Базовые примеры
CustomElementRegistry
хранит список определенных пользовательских элементов. Этот объект позволяет регистрировать новые пользовательские элементы на странице и возвращать информацию о зарегистрированных пользовательских элементах и т.д.
Для регистрации нового пользовательского элемента на странице используется метод CustomElementRegistry.define()
. Он принимает следующие аргументы:
- Строчку, отображающую имя элемента (слова нельзя разделять пробелами, только дефисом).
- Объект класса, определяющий поведение элемента.
- Дополнительный аргумент, содержащий свойство
extends
, определяющее встроенный элемент, которому наследует новый элемент (если таковой имеется).
Пользовательский элемент задается так:
class WordCount extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({
mode: 'open'
});
const span = document.createElement('span');
span.textContent = this.getAttribute('text').split(' ').length;
const style = document.createElement('style');
style.textContent = 'span { color: red }';
shadow.appendChild(style);
shadow.appendChild(span);
}
}
customElements.define('word-count', WordCount);
В коде выше мы подключили теневой DOM к документу, вызвав attachShadow
. Режим mode
'open'
означает, что теневой корень доступен из JavaScript вне корня. Режим также может быть 'closed'
с противоположным поведением.
Затем мы создали элемент span
, где задали текстовое содержимое для атрибута text
length
после разделения слов пробелами.
Далее создали элемент style
и задали содержимое color: red
.
Наконец, мы присоединили их к корню теневого DOM.
Заметьте, что в нашем классе мы расширяем HTMLElement
. Это необходимо для определения пользовательского элемента.
Использовать новый элемент можно следующим образом:
<word-count text='Hello world.'></word-count>
Существуют 2 типа пользовательских элементов:
- Автономные пользовательские элементы — независимые, не наследуют от стандартных HTML элементов. Их можно создать, ссылаясь напрямую на имя. Например, написать
<word-count>
илиdocument.createElement("word-count")
. - Настраиваемые встроенные элементы— наследуют от базовых HTML элементов. Для создания подобных элементов расширяем один из встроенных HTML элементов, например, написав
<p is="word-count">
илиdocument.createElement("p", { is: "word-count" })
.
Пользовательский элемент, созданный выше — автономный. Настраиваемый элемент создается так:
class WordCount extends HTMLParagraphElement {
constructor() {
super();
const shadow = this.attachShadow({
mode: 'open'
});
const span = document.createElement('span');
span.textContent = this.getAttribute('text').split(' ').length;
const style = document.createElement('style');
style.textContent = 'span { color: red }';
shadow.appendChild(style);
shadow.appendChild(span);
}
}
customElements.define('word-count', WordCount, {
extends: 'p'
});
Чтобы поместить его на страницу, пишем:
<p is='word-count' text='Hello world.'></p>
Как видите, автономные и настраиваемые элементы не сильно отличаются друг от друга. Единственное отличие — мы расширяем HTMLParagraphElement
, а не HTMLElement
.
Затем используем атрибут is
для ссылки на пользовательский элемент вместо использования имени элемента в настраиваемом встроенном элементе.
Внутренние или внешние стили
Мы также можем ссылаться на внешние стили вместо использования внутренних, как сделано выше. Например, напишем:
const linkElem = document.createElement('link');
linkElem.setAttribute('rel', 'stylesheet');
linkElem.setAttribute('href', 'style.css');
shadow.appendChild(linkElem);
Мы ссылаемся на стили из style.css
. Элемент link
создается так же, как в HTML и нормальном DOM.
Создавать веб-компоненты просто. Нужно задать класс или функцию для определения функциональности и затем поместить их в реестр пользовательских элементов, используя метод customElements.define
.
Мы можем расширить существующие элементы, такие как p
, или создать новые с нуля. Также мы можем добавлять внутренние стили или ссылаться на внешние, создавая элемент link
и ссылаясь на внешние файлы.
Читайте также:
- Веб-сервер с нуля в TypeScript и Node
- Лучшие практики JavaScript: переменные
- Почему мы не используем лучшие практики CI/CD
Перевод статьи John Au-Yeung: Introduction to Creating Web Components