Понимание веб-компонентов и пользовательских элементов в HTML

Понимание веб-компонентов и пользовательских элементов в 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

Точно так же вы можете создавать свои собственные элементы и использовать их где угодно.


Также опубликовано здесь.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE