Web Components
Шаблонизаторы и пользовательские тэги.
Web Components
Templates
01. <template>
<img src="logo.png"/>
<div class="comment"></div>
04. </template>
02.
03.
Преимущества <template>
активировано. По сути разметка является скрытым DOM'ом и не рендерится.
querySelector() или document.getElementById() .
Пример <template>
Пример <template>
<template> и стили
Custom Elements
Одна из ключевых особенностей стандарта Веб-компонент это возможность создавать пользовательские элементы на HTML-странице, инкапсулирующие функциональность, вместо того чтобы создавать длинную, вложенную группу элементов, которые бы вместе реализовывали нужную пользовательскую фичу
Yandex.Mail
Yandex.Mail
Yandex.Mail
Верстка яндекс почты без WebComponents
Верстка яндекс почты c WebComponents
Пример кастомного элемента
Неразрешённые (Unresolved) элементы
Так как регистрация кастомных элементов происходит путём вызова document.registerElement() в тэгах script, а построение DOM ещё до вызова script’ов, мы можем столкнуться с такой вещью как неразрешённые элементы.
Если мы попытаемся использовать кастомный элемент до регистрации, то такой элемент будет считаться неразрешённым.
Всплывает событие unresolved
Lifecycle callbacks
connectedCallback
экземпляр элемента добавлен в документ
disconnectedCallback
экземпляр элемента удалён из документа
adoptedCallback
экземпляр элемента был перемещён в новый документ
attributeChangedCallback(attrName, oldVal, newVal)
добавление/удаление/изменение аттрибута attrName
attributeChangedCallback
Теневой DOM («Shadow DOM»)
Используется для инкапсуляции. �Благодаря ему в компоненте есть собственное «теневое» DOM-дерево, к которому нельзя просто так обратиться из главного документа, у него могут быть изолированные CSS-правила и т.д.
.attachShadow()
Вызов elem.attachShadow({mode: …}) создаёт теневое дерево.
Есть два ограничения:
.attachShadow({ mode: … })
Свойство mode задаёт уровень инкапсуляции. �У него может быть только два значения:
Любой код может получить теневое дерево элемента «elem»
До теневого DOM в таком случае мы сможем добраться только по ссылке, которую возвращает attachShadow.
Встроенные браузерные теневые деревья, такие как у �<input type="range">, по умолчанию закрыты.
Програмнно из JS-a до них не добраться.
Инкапсуляция теневого DOM
Теневой DOM отделён от главного документа:,
Слоты теневого DOM (композиция).
Слоты теневого DOM (композиция).
Многим типам компонентов, таким как вкладки, меню, галереи изображений и другие, нужно какое-то содержимое для отображения.
Так же, как встроенный в браузер <select> ожидает получить контент пунктов <option>, компонент <custom-tabs> может ожидать, что будет передано фактическое содержимое вкладок, а <custom-menu> – пунктов меню.
Код, использующий меню <custom-menu>, может выглядеть так:
Именованные слоты
В теневом DOM <slot name="X"> определяет «точку вставки» – место, где отображаются элементы с slot="X".
Затем браузер выполняет «композицию»: берёт элементы из обычного DOM-дерева и отображает их в соответствующих слотах теневого DOM-дерева. В результате мы получаем именно то, что хотели – компонент, который можно наполнить данными.
После выполнения скрипта структура DOM выглядит следующим образом (без учёта композиции):
Именованные слоты
Чтобы отобразить содержимое, для каждого <slot name="..."> в теневом DOM браузер ищет slot="..." с таким же именем в обычном DOM. Эти элементы отображаются внутри слотов:
Развёрнутое DOM-дерево
…но развёрнутое DOM-дерево существует только для целей отображения и обработки событий. Это то, что мы видим на экране. Оно, в некотором плане, «виртуальное». Фактически в документе расположение узлов не меняется.
Это можно легко проверить, запустив querySelectorAll: �все узлы находятся на своих местах.
document.querySelectorAll('user-card span').length; // 2
Слот по умолчанию
Первый <slot> в теневом дереве без атрибута name является слотом по умолчанию. Он будет отображать данные со всех узлов светлого дерева, не добавленные в другие слоты
Например, давайте добавим слот по умолчанию в наш элемент <user-card>; он будет собирать всю информацию о пользователе, не занесённую в другие слоты
Обновление слотов
Что если внешний код хочет динамически реагировать на изменение данных в слотах?
Браузер наблюдает за слотами и обновляет отображение при добавлении и удалении элементов автоматически.
Таким образом, нам ничего не нужно делать для обновления отображения. Но если код компонента хочет узнать об изменениях в слотах, можно использовать событие slotchange.
API слотов
Как мы видели раньше, JavaScript смотрит на «реальный», а не на развёрнутый DOM. Но если у теневого дерева стоит {mode: 'open'}, то мы можем выяснить, какие элементы находятся в слоте, и, наоборот, определить слот по элементу, который в нём находится:
Стилизация WebComponent’ов
Теперь, когда мы представляем себе на устроен веб компонент внутри, самое время поговорить об их стилизации.
Селекторы для веб компонентов
WebComponents
https://xrem.github.io/web/web-component-example.html
Что дальше?
Больше веб-компонентов без framework’ов:
Либо, отдельно шаблонизаторы (handlebars, ejs, etc…)
Либо, полноценные UI Framework’и: Vue, React, Angular.
Время вопросов
Спасибо за внимание