Понимание веб-компонентов и пользовательских элементов в HTML
4 января 2024 г.Те, кто знаком с React или любой другой средой JavaScript, уже знают о компонентной архитектуре. Вы разбиваете пользовательский интерфейс на фрагменты кода, которые можно использовать повторно, и при необходимости сшиваете их вместе.
Пользовательские элементы в HTML – это способ расширения собственных элементов HTML. Фреймворки Javascript имитируют поведение компонентов на веб-странице, тогда как пользовательские элементы предоставляют для этого собственный HTML-способ. Веб-компонент использует пользовательские элементы наряду с другими методами, такими как теневое DOM.
Типы пользовательских элементов #
- Автономные пользовательские элементы
- Настраиваемые встроенные элементы
Автономные пользовательские элементы расширяют общий класс HTMLElement. С другой стороны, настраиваемый пользовательский элемент расширяет класс определенного элемента HTML и строится на основе существующих функций. Например, если вам нужен собственный элемент привязки, вы можете расширить HTMLAnchorElement.< /п>
Определение пользовательских элементов #
Чтобы определить пользовательский элемент, нам нужно создать класс JavaScript, расширяющий собственный класс HTMLElement. Попробуйте создать приведенный ниже пользовательский элемент с помощью ручки кода:
class Demo extends HTMLElement {
constructor() {
super()
}
connectedCallback() {
this.textContent = "hello"
}
}
customElements.define("demo", Demo)
А затем вызовем его в HTML:
<demo></demo>
Он не позволит вам создать его. Почему? Посмотрите ошибку.
Uncaught SyntaxError: Failed to execute 'define' on 'CustomElementRegistry': "demo" is not a valid custom element name
Это не ошибка, это сделано намеренно, чтобы отделить пользовательские элементы от собственных элементов HTML. Пользовательские элементы должны содержать дефис в своем имени, чтобы пользовательские элементы были узнаваемы и отличались от элементов HTML.
Итак, если вы измените его на что-то вроде demo-webc
и измените имя класса на DemoWebC
, это сработает.
class DemoWebC extends HTMLElement {
constructor() {
super()
this.customProperty = "custom"
}
connectedCallback() {
this.textContent = "hello"
}
}
// two arguments: tag name, class name
customElements.define("demo-webc", DemoWebC)
Всегда рекомендуется сначала вызывать метод super()
в конструкторе, поскольку он инициализирует свойства по умолчанию класса HTMLElement
, вызывая его конструктор.
Метод connectedCallback()
предназначен для определения момента загрузки элемента на страницу. Также существует метод disconnectedCallback()
, который определяет, удален ли элемент со страницы. Имя третьего метода adoptedCallback()
сообщает, что элемент переместился на новую страницу.
Вы можете определить собственные свойства внутри конструктора и использовать их в качестве пользовательских атрибутов в своем элементе.
constructor() {
super()
this.customProperty = {
name: "data-custom",
value: "custom value"
}
connectedCallback() {
this.textContent = "hello"
this.setAttribute(this.customAttribute.name, this.customAttribute.value)
}
}
Но что, если вам нужно изменить функциональность изменения значения атрибута? Именно здесь в действие вступает метод attributeChangedCallback()
. Чтобы увидеть это в действии, вам нужно сначала определить статическое свойство класса observedAttributes
и установить для него массив всех атрибутов, которые вы хотите отслеживать.
attributeChangedCallback()
срабатывает, если изменяются атрибуты, упомянутые в статическом свойстве observedAttributes
. Обратите внимание: если атрибут уже присутствует при загрузке пользовательского элемента, этот метод также запускается в этот момент.
static observedAttributes = ["data-custom"]
constructor() {
super()
}
attributeChangedCallback(name, old, newValue) {
console.log(name, old, newValue)
}
Закончив создание пользовательского элемента, вы должны зарегистрировать его с помощью метода define()
. Его можно вызвать для глобального объекта customElements
(window.customElements
), который представляет собой реестр пользовательских элементов.
customElements.define("custom-element-name", ClassName, options)
Все это было сделано для определения индивидуального автономного пользовательского элемента. А как насчет расширения только привязки HTML-элемента?
Для этого вместо расширения класса HTMLElement
расширьте класс HTMLAnchorElement
. И укажите, какой тип HTML-элемента он расширяет, с помощью параметра extends
.
class DemoAnchor extends HTMLAnchorElement {
constructor() {
super()
}
connectedCallback() {
this.textContent = "syntackle.live"
this.href = "https://syntackle.live"
}
}
customElements.define("demo-anchor", DemoAnchor, { extends: "a" })
Вы не можете использовать этот элемент как <demo-anchor>
, поскольку он не является автономным элементом, вместо этого вы можете использовать его следующим образом:
<a is="demo-anchor"></a>
Веб-компоненты #
Веб-компоненты — это больше, чем просто пользовательские элементы. Иногда они также включают теневой DOM. Теневой DOM, как следует из названия, представляет собой поддерево DOM для элементов HTML. В основном он используется для инкапсуляции и ограничения стилей только веб-компонентом.
Теневой DOM
Чтобы создать теневой DOM, прикрепите его к хосту, в нашем случае пользовательский элемент сам является хостом теневого DOM. Однако теневой DOM можно прикрепить только к пользовательскому элементу или этим встроенным элементам, упомянутым в спецификации HTML< /а>.
<блок-цитата>Вы можете получить доступ к элементам за пределами теневого DOM изнутри теневого DOM.
class DemoWebC extends HTMLElement {
constructor() {
super()
}
connectedCallback() {
const shadow = this.attachShadow({mode: "open"})
const style = document.createElement("style")
style.textContent = `p { color: blue; }`
shadow.appendChild(style)
const text = document.createElement("p")
text.textContent = "hello"
shadow.appendChild(text)
}
}
customElements.define("demo-webc", DemoWebC)
Shadow DOM имеет два режима: открытый
и закрытый
. Открытость означает, что внешние элементы на странице могут изменять содержимое теневого DOM с помощью свойства shadowRoot
. В режиме закрыто
теневой DOM недоступен извне с помощью свойства shadowRoot
, поскольку в данном случае оно имеет значение null
.
Попробуйте сделать это с закрытым теневым пользовательским элементом DOM:
console.log(document.querySelector("demo-webc").shadowRoot)
Он возвращает null
.
Шаблоны и слоты чрезвычайно полезны при создании сложных пользовательских элементов или веб-компонентов. Подробное их изучение выходит за рамки этой статьи, но вот несколько хороших ресурсов для них:
* Использование шаблонов и слотов — Веб-API | МДН * Теневые слоты DOM, композиция * Работа со слотами и веб-компонентами
Стилизация теневого DOM
Теневой DOM может быть стилизован следующим образом:
* Создание объекта CSSStyleSheet
, вставка в него CSS с помощью replaceSync()
и прикрепление его к теневой модели DOM с помощью свойства adoptedStyleSheets
.
<код>JavaScript constshadowDOM = this.attachShadow({режим: «открыть»}) const styleSheet = новый CSSStyleSheet() styleSheet.replaceSync(p {color: blue; }) shadowDOM.adoptedStyleSheets = [styleSheet]
* Объявление стилей с помощью <template>
.
<код>разметка <template id="custom"> <голова> <стиль>p { цвет: синий; }</style> </голова> <p>Веб-компонент</p> </template>
<код>JavaScript constshadowDOM = this.attachShadow({режим: "открыть" }) const шаблон = document.querySelector("#custom") shadowDOM.appendChild(template.content.cloneNode(true))
* Просто создайте тег style
и вставьте в него CSS как текст.
<код>JavaScript const style = document.createElement("стиль") style.textContent = p { цвет: синий; } shadow.appendChild(стиль)
Создание собственного веб-компонента #
Первый веб-компонент, показанный ниже, представляет собой настраиваемый элемент кнопки, который открывает элемент dialog
. А второй веб-компонент включает в себя теневую DOM для красивой печати строк JSON в HTML.
https://codepen.io/seekertruth/pen/LYaYqmo?embedable=true р>
Точно так же вы можете создавать свои собственные элементы и использовать их где угодно.
Также опубликовано здесь.
Оригинал