Русский
Русский
English
Статистика
Реклама

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

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

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

И в процессе углубления я понял: веб-компоненты проще, чем я думал.

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

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

Начнем с <template>

<template> - это HTML элемент, позволяющий создать нам шаблон (HTML структуру для веб-компонентов).

Код
<template>  <p>The Zombies are coming!</p></template>

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

Тогда есть компонент <slot>

<slot> - это всего лишь другой HTML элемент, как и <template>. Но в нашем случае <slot> настраивает то, что <template> отображает на странице.

Код
<template>  <p>The <slot>Zombies</slot> are coming!</p></template>

Здесь мы добавили слот с словом "Zombies" (Слово ли это?) в разметку <template>. Если мы ничего не делаем со слотом, по умолчанию он отображает контент между тегами. В нашем случае это будет "Zombies".

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

Код
<template>  <p>The <slot name="whats-coming">Zombies</slot> are coming!</p></template>

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

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

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

Код
<apocalyptic-warning>  <span slot="whats-coming">Halitosis Laden Undead Minions</span></apocalyptic-warning><template>  <p>The <slot name="whats-coming">Zombies</slot> are coming!</p></template>

Видите, что мы делаем? Мы помещаем <apocalyptic-warning> компонент на страницу так же, как и любой другой HTML элемент. Однако мы добавили <span> в слот "whats-coming". <span> и его содержимое будет отображено на месте "Zombies", когда компонент отобразится.

Стоит обратить внимание, что в названиях веб-компонентов должен быть дефис, чтобы предотвратить конфликт с HTML элементами, которые могут быть добавлены позже. Это то, о чем вы должны знать, когда дело касается веб-компонентов.

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

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

Как я уже сказал ранее, вам нужно немного JavaScript кода, чтобы все это работало, но это не очень сложный, многострочный и глубокий код, как я всегда думал. Надеюсь, я смогу убедить вас.

Вам нужна функция-конструктор, которая регистрирует веб-компонент. Иначе наше компоненты будет как нежить: она есть, но не полностью живая.

Вот конструктор, который мы будем использовать.

Код
// Определяем кастомный веб-компонент с подходящим именемcustomElements.define("apocalyptic-warning", class extends HTMLElement {    // Наследование обеспечивает, что мы имеет свойства и методы по умолчанию встроенного HTML    элемента    // Вызывается всякий раз, когда создаеся новый элемент    constructor() {      // Выываем родительский конструктор, т.е конструктор для HTMLElement. Таким образом   устанавливаются свойства базового HTML элемента.      super();      // Берет <template> и хранит его в переменной `warinng`      let warning = document.getElementById("warningtemplate");            // Хранит контент шаблона в переменной `mywarning`      let mywarning = warning.content;      const shadowRoot = this.attachShadow({mode: "open"}).appendChild(mywarning.cloneNode(true));    }});

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

Код
const shadowRoot = this.attachShadow({mode: "open"}).appendChild(mywarning.cloneNode(true));

Мы здесь делаем много работы. Во-первых, мы берем наш веб-компонент (this) и создаем скрытого шпиона, я имею в виду Shadow DOM.{ mode: open } означает, что JavaScript может извне :root обращаться к элементам Shadow DOM и управлять ими, что-то вроде настройки доступа к компоненту через черный вход. Был создан Shadow DOM и мы добавляем к ней узел (Примечание переводчика: HTML Node). Этот узел будет полной копией шаблона, включая все элементы и текст шаблона. С шаблоном, прикрепленным к Shadow DOM из пользовательского компонента, элемент <slot> и slot атрибут берут на себя задачу сопоставления содержимого с тем, где оно должно находиться.

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

Код

JS:

customElements.define('apocalyptic-warning',    class extends HTMLElement {      constructor() {        super();        let warning = document.getElementById('warningtemplate');        let mywarning = warning.content;                 const shadowRoot = this.attachShadow({mode: 'open'}).appendChild(mywarning.cloneNode(true));              }    });

HTML:

<p>The Apocalypse will never happen!</p><apocalyptic-warning>   <span slot="whats-coming">Undead</span></apocalyptic-warning><apocalyptic-warning>   <span slot="whats-coming">Halitosis Laden Zombie Minions</span></apocalyptic-warning><template id="warningtemplate">  <style>    p {      background-color: pink;      padding: 0.5em;      border: 1px solid red;    }  </style>    <p>The <slot name="whats-coming">Zombies</slot> are coming!</p></template>

Пример: Codepen

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

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

Код
<template id="warningtemplate">  <style>    p {      background-color: pink;      padding: 0.5em;      border: 1px solid red;    }  </style>    <p>The <slot name="whats-coming">Zombies</slot> are coming!</p></template>

Таким образом, стили применяются только для компонента, что позволяет изолировать их благодаря теневой модели Shadow DOM.

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

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

Код
apocalyptic-warning span {  color: blue;}

Будьте осторожны, стили в основном файле CSS не могут получить доступ к внутренним элементам <template>.

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

Код
customElements.define("zombie-profile",  class extends HTMLElement {    constructor() {      super();      let profile = document.getElementById("zprofiletemplate");      let myprofile = profile.content;      const shadowRoot = this.attachShadow({mode: "open"}).appendChild(myprofile.cloneNode(true));    }  });

Вот шаблон HTML и инкапсулированный CSS.

Код
<template id="zprofiletemplate">  <style>    img {      width: 100%;      max-width: 300px;      height: auto;      margin: 0 1em 0 0;    }    h2 {      font-size: 3em;      margin: 0 0 0.25em 0;      line-height: 0.8;    }    h3 {      margin: 0.5em 0 0 0;      font-weight: normal;    }    .age, .infection-date {      display: block;    }    span {      line-height: 1.4;    }    .label {      color: #555;    }    li, ul {      display: inline;      padding: 0;    }    li::after {      content: ', ';    }    li:last-child::after {      content: '';    }    li:last-child::before {      content: ' and ';    }  </style>  <div class="profilepic">    <slot name="profile-image"><img src="http://personeltest.ru/aways/assets.codepen.io/1804713/default.png" alt=""></slot>  </div>  <div class="info">    <h2><slot name="zombie-name" part="zname">Zombie Bob</slot></h2>    <span class="age"><span class="label">Age:</span> <slot name="z-age">37</slot></span>    <span class="infection-date"><span class="label">Infection Date:</span> <slot name="idate">September 12, 2025</slot></span>    <div class="interests">      <span class="label">Interests: </span>      <slot name="z-interests">        <ul>          <li>Long Walks on Beach</li>          <li>brains</li>          <li>defeating humanity</li>        </ul>      </slot>    </div>    <span class="z-statement"><span class="label">Apocalyptic Statement: </span> <slot name="statement">Moooooooan!</slot></span>  </div></template>

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

Код
zombie-profile {  width: calc(50% - 1em);  border: 1px solid red;  padding: 1em;  margin-bottom: 2em;  display: grid;  grid-template-columns: 2fr 4fr;  column-gap: 20px;}zombie-profile img {  width: 100%;  max-width: 300px;  height: auto;  margin: 0 1em 0 0;}zombie-profile li, zombie-profile ul {  display: inline;  padding: 0;}zombie-profile li::after {  content: ', ';}zombie-profile li:last-child::after {  content: '';}zombie-profile li:last-child::before {  content: ' and ';}

А вот и результат:

Пример: Codepen

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

Вот и все. Чего вы сейчас боитесь больше: веб-компонентов или зомби-апокалипсиса? В недалеком прошлом я бы мог сказать, что веб-компонентов, но теперь зомби - единственное, что меня беспокоит (Ну, и покроют ли мои суточные выплаты закуски).

Источник: habr.com
К списку статей
Опубликовано: 14.03.2021 20:05:08
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Css

Javascript

Html

Web components

Разработка сайтов

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru