Веб-компоненты проще, чем вы думаете

От автора: когда я ходил на конференции и смотрел, как кто-то делает презентацию о веб-компонентах, я всегда думал, что это было довольно здорово (да, очевидно, я из 1950 года), и это всегда казалось мне очень сложным. Тысяча строк JavaScript, чтобы сэкономить четыре строки HTML. Докладчик неизбежно либо замалчивал уйму JavaScript, который заставляет это работать, либо они вдавались в мучительные детали, и мои глаза наполнялись грустью от непонимания того, о чем говорят.

Но в недавнем справочном проекте, призванном упростить изучение HTML (конечно, путем проб и ошибок), я решил, что мне нужно познакомится с каждым элементом HTML в спецификации. Помимо этих конференций, это было мое первое знакомство с элементами <slot> и <template>. Но для написания чего-нибудь простенького и увлекательного, пришлось копнуть немного глубже.

И я кое-что узнал в процессе: веб-компоненты намного проще, чем кажутся. Либо веб-компоненты прошли долгий путь с тех пор, как я в последний раз поймал себя на мечтах о работе с ними на конференции, либо я позволил своему первоначальному страху перед ними помешать по-настоящему узнать их — возможно, и то и другое.

Я здесь, чтобы сказать вам, что вы — да, вы — можете создать веб-компонент. Давайте на мгновение оставим наши отвлекающие факторы и страхи, давайте сделаем это вместе.

Начнем с <template>

A <template> — это элемент HTML, который позволяет нам создать, шаблон — структуру HTML для веб-компонента. Шаблон не обязательно должен быть огромным фрагментом кода. Он может быть очень простой:

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Узнать подробнее

Элемент <template> имеет важное значение, потому что он связывает все вместе. Это как фундамент здания; это база, на которой построено все остальное. Давайте использовать этот небольшой фрагмент HTML в качестве шаблона для нашего веб-компонента <apocalyptic-warning> — в качестве предупреждения, когда на нас надвигается зомби-апокалипсис.

Элемент <slot>

<slot> это просто еще один элемент HTML, как и <template>. Но в этом случае <slot> настраивает то, как <template> отображается на странице.

Здесь мы вставили слово «Zombies» в шаблонную разметку. Если мы ничего не делаем с тегом slot, по умолчанию используется содержимое между тегами.

Использование slot очень похоже на заполнитель. Мы можем использовать заполнитель как есть или вместо него указать что-нибудь другое. Мы делаем это с помощью атрибута name.

Атрибут name сообщает о веб-компоненте, содержание которого описано в шаблоне. Прямо сейчас у нас есть слот под названием whats-coming. Мы предполагаем, что зомби придут первыми в апокалипсисе, но этот slot дает нам некоторую гибкость, чтобы вставить что-то еще, например, если это будет робот, оборотень или даже апокалипсисом веб-компонентов.

Использование компонента

Технически мы закончили «писать» компонент и можем вставить его в любое место, где захотим.

Видите, что мы там сделали? Мы поместили компонент <apocalyptic-warning> на страницу точно так же, как любой другой div или что-то еще. Но мы также добавили в span ссылку на name атрибут нашего slot. И то, что между ними, в span мы можем заменить на «Zombies» при рендеринге компонента.

Вот небольшая ошибка, на которую стоит обратить внимание: в именах пользовательских элементов должен быть дефис. Это просто одна из тех вещей, которые вам нужно знать. Спецификация предписывает это для предотвращения конфликтов в случае, если в HTML появится элемент с тем же именем.

Вы все еще со мной? Не так уж и страшно, правда? Ну, если не считать зомби. Нам еще предстоит немного поработать, чтобы сделать замену slot возможной, и именно здесь мы начинаем разбираться с JavaScript.

Регистрация компонента

Как я уже сказал, вам нужен некоторый JavaScript, чтобы все это работало, но это не сверхсложный, многострочный и глубокий код, как я думал раньше. Надеюсь, я смогу убедить и вас. Вам нужна функция-конструктор, регистрирующая пользовательский элемент. Вот конструктор, который мы будем использовать:

Я привёл подробные комментарии, которые объясняют все построчно. Кроме последней строки:

Мы здесь много делаем. Во-первых, мы берем наш custom element (this) и создаем скрытого агента — я имею в виду теневой DOM. mode: open просто означает, что JavaScript извне :root может обращаться к элементам в теневой DOM и манипулировать ими, что-то вроде настройки доступа к компоненту через черный ход.

Была создана теневая DOM, и мы добавили к ней узел. Этот узел есть полной копией шаблона, включая все элементы и текст шаблона. Из шаблона, прикрепленного к теневому DOM пользовательского элемента, подбирается содержимое атрибута slot и подставляется на свое место.

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Узнать подробнее

Проверь это. Теперь мы можем объединить два экземпляра одного и того же компонента, отображая разный контент, просто изменив один элемент.

Стилизация компонента

Возможно, вы заметили стиль в этой демонстрации. Как и следовало ожидать, у нас есть абсолютная возможность стилизовать наш компонент с помощью CSS. Фактически, мы можем включить элемент style прямо в template.

Таким образом, стили ограничиваются непосредственно компонентом, и ничего не просачивается в другие элементы на той же странице благодаря теневой модели DOM.

Я предполагал, что пользовательский элемент берет копию шаблона, вставляет добавленный нами контент, а затем внедряет его на страницу с помощью теневой модели DOM. Хотя так это выглядит во внешнем интерфейсе, на самом деле это не верно. Контент в пользовательском элементе остается прямо на месте, а теневой DOM как бы накладывается сверху, как наложение.

Веб-компоненты проще, чем вы думаете

А поскольку содержимое технически находится за пределами шаблона, любые дочерние селекторы или классы, которые мы используем в элементе шаблона style, не будут влиять на содержимое, размещенное в slot. Это не позволяет обеспечить полную инкапсуляцию, как я ожидал. Но поскольку пользовательский элемент является элементом, мы можем использовать его в качестве селектора элемента в любом файле CSS, включая основную таблицу стилей, используемую на странице. И хотя вставленный материал технически не находится в шаблоне, он находится в пользовательском элементе, и селекторы потомков из CSS будут работать.

Но будьте осторожны! Стили в основном файле CSS не могут получить доступ к элементам в template теневой модели DOM.

Соберем все это вместе

Давайте посмотрим на пример, скажем, профиль для службы знакомств с зомби, вроде того, который вам может понадобиться после апокалипсиса. Чтобы стилизовать и содержимое по умолчанию и любой вставленный контент, нам нужен элемент style в template и стили в файле CSS.

Код JavaScript точно такой же, за исключением того, что сейчас мы работаем с другим именем компонента, <zombie-profile>.

Вот шаблон HTML, включая инкапсулированный CSS:

Вот CSS для нашего элемента <zombie-profile> и его потомков из нашего основного файла CSS. Обратите внимание на дублирование, чтобы гарантировать, что и замененные элементы, и элементы из шаблона имеют одинаковый стиль.

Теперь все собрано вместе!

Несмотря на то, что есть еще несколько ошибок и других нюансов, я надеюсь, что вы увидели больше возможностей работать с веб-компонентами сейчас, чем несколько минут назад. Возможно, добавьте в свою работу нестандартный компонент, чтобы почувствовать его и понять, где это имеет смысл.

Это действительно так. Чего вы боитесь больше, веб-компонентов или зомби-апокалипсиса? Я мог бы сказать, что в недалеком прошлом боялся веб-компонентов, но теперь я с гордостью могу сказать, что зомби — единственное, что меня беспокоит.

Автор: John Rhea

Источник: css-tricks.com

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Узнать подробнее

React JS с Нуля до Профи

React JS. Полное руководство для современной веб-разработки

Подробнее

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии Facebook:

Комментирование закрыто.