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

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

Шаблоны

Мы можем использовать элемент template для добавления контента, который не отображается в DOM. Это позволяет нам включить их в любой другой элемент, написав следующий HTML-код:

<template>
  <p>Foo</p>
</template>

Затем мы можем написать следующий код JavaScript, чтобы включить его на страницу:

const template = document.querySelector('template');
const templateContent = template.content;
document.body.appendChild(templateContent);

Когда мы загружаем страницу, мы должны видеть «Foo» на странице. Элемент p должен отображаться, когда мы проверяем код для «Foo». Это подтверждает, что элемент template не влияет на разметку.

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

Мы также можем использовать их с веб-компонентами. Чтобы использовать его, мы можем получить элемент template в классе для веб-компонента точно так же, как мы это делаем вне веб-компонента.

Например, мы можем написать:

customElements.define('foo-paragraph',
  class extends HTMLElement {
    constructor() {
      super();
      let template = document.querySelector('template');
      let templateContent = template.content;
      const shadowRoot = this.attachShadow({
          mode: 'open'
        })
        .appendChild(templateContent.cloneNode(true));
    }
  })

В приведенном выше коде мы получаем элемент template и вызов cloneNode для templateContent, который имеет template.content в качестве значения для получения содержимого шаблона.

Затем мы вызываем cloneNode для клонирования дочерних узлов template.content в дополнение к самому узлу. На это указывает аргумент true вызова функции cloneNode.

Наконец, мы прикрепили клонированный templateContent к теневому корню веб-компонента с помощью методов attachShadow и appendChild.

Мы также можем включить стиль в элемент template, чтобы мы могли повторно использовать его, как мы это делаем с разметкой HTML.

Например, мы можем изменить элемент template на:

<template>
  <style>
    p {
      color: white;
      background-color: gray;
      padding: 5px;
    }
  </style>
  <p>Foo</p>
</template>

Тогда мы должны увидеть:

Слоты

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

У него более ограниченная поддержка, чем у шаблонов. Слоты можно использовать с Chrome 53 или новее, Opera с версии 40, Firefox с версии 59 и не поддерживается в Edge.

Например, мы можем добавить несколько слотов, написав:

<template>
  <slot name="foo">Default text for foo</slot>
  <slot name="bar">Default text for bar</slot>
  <slot name="baz">Default text for baz</slot>
</template>

Затем, учитывая, что у нас есть тот же код, что и раньше, для определения элемента foo-paragraph в JavaScript, мы можем использовать его следующим образом:

<foo-paragraph>
  <p slot='foo'>foo</p>
  <p slot='bar'>bar</p>
  <p slot='baz'>baz</p>
</foo-paragraph>

Результатом будет:

foo
bar
baz

Если мы опустим элементы внутри тегов foo-paragraph, мы получим текст по умолчанию:

Default text for foo Default text for bar Default text for baz

В приведенном выше коде мы называем слоты атрибутом name в элементе template, затем в нашем веб-компоненте мы заполняем слоты, которые мы определили с помощью атрибута slot.

Мы можем стилизовать их как любой другой элемент template. Чтобы стилизовать их, мы выбираем элементы, которые будут стилизованы, с помощью селектора для элементов, которые мы заполняем в гнездах.

Например, мы можем написать:

<template>
  <style>
    ::slotted(p) {
      padding: 5px;
      background-color: black;
      color: white;
    }
    ::slotted(p[slot='foo']) {
      background-color: gray;
    }
  </style>
  <slot name="foo">Default text for foo</slot>
  <slot name="bar">Default text for bar</slot>
  <slot name="baz">Default text for baz</slot>
</template>
<foo-paragraph>
  <p slot='foo'>foo</p>
  <p slot='bar'>bar</p>
  <p slot='baz'>baz</p>
</foo-paragraph>

Псевдоэлемент ::slotted представляет элементы, которые были помещены в слот внутри шаблона HTML. Следовательно, мы можем использовать его для выбора элементов слота, которые мы хотим стилизовать.

В аргументе ::slotted мы можем передать элемент, который мы хотим стилизовать, если он был передан в слот. Это означает, что только p элементов, которые передаются, будут иметь стили, примененные к ним.

::slotted(p[slot=’foo’]) означает, что к элементу p со значениями атрибутов slot foo будет применен стиль.

Тогда после применения стилей у нас должно получиться следующее:

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

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

В любом случае мы можем применять стили к элементам по своему желанию. У нас есть псевдоэлемент ::slotted для применения стилей к определенным элементам в слотах.