Главная » Хабрахабр » Веб-компоненты. Часть 3: html шаблоны и импорты

Веб-компоненты. Часть 3: html шаблоны и импорты

Вступление

Данная статья является третьей и последней статьей в серии статей о веб-компонентах.Первые две статьи доступны по ссылкам: Приветствую коллеги.

Веб компоненты. Часть 1: Пользовательские элементы
Веб-компоненты. Часть 2: Теневой DOM

В данной статье речь пойдет о <template> элементе а также об HTML импортах.

HTML Templates элемент

Элемент <template> представляет собой инструмент, позволяющий хранить контент на стороне клиента без его рендеринга на страницу, однако с возможностью его отображения в процессе исполнения посредством JavaScript.

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

Содержимое <template>

Это означает, что в содержимом шаблона можно, например, указать элемент img не указав значение атрибутов src и alt, таким образом: К содержимому <template>, как и к любому узлу, не имеющему браузерного контекста, не применимы никакие требования соответствия, кроме требований к правильности HTML и XML синтаксиса.

<template> <div> <img src="}" alt="{{alt}}"> </div> </template>

При этом пропуск закрывающего тега </div> был бы нарушением HTML синтаксиса и не является допустимым для содержимого <template>. однако, вне элемента <template> такой синтаксис валидным не является.

Все элементы указанные внутри тега <template> в html коде не являются его дочерними элементами.

approptiate template contents owner document, определяемый по этому алгоритму, документа в котором указан <template> и указывает значением свойства .content созданный DocumentFragment. Бразуеры при создании элемента <template> создают DocumentFragment чьим документом является т.н.

То есть свойство .content у элемента template содержит DocumentFragment, и элементы, которые в html коде были указаны внутри тегов <template> являются дочерними элементами именно этого DocumentFragment.

При этом элементу <template>, как и любому другому, можно добавить дочерние элементы (appendChild()), но это будет считаться нарушение модели содержимого шаблона.

Клонирование шаблона

При клонирования содержимого шаблона важно помнить, что первый аргумент в .cloneNode([deep])
или второй в .importNode(externalNode, deep) передавать обязательно надо (согласно спецификации, если аргумент не будет передан, дальнейшее выполнение происходить не должно).

Разница только в том, когда документ обновится (для .cloneNode() — после вызова appendChild(); для .importNode() — после клонирования). Кстати, да, не смотря на то что большинство примеров используют именно .cloneNode(), использование .importNode() тоже возможно.

Show me the code ©

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

Начинать я буду с того, что создам в html разметке два элемента <template> и перенесу в них ту разметку, что была в методе .render() классов TabNavigationItem и TabContentItem (я также изменила некоторые стили но на функциональность это не влияет):

<template id="tab-nav"> <style> :host{ padding: 10px; background-color: rgb(81,180,186); transition: background-color 1s; text-align: center; } :host-context(.active) { background-color: rgb(93, 209, 216); } a{ text-decoration: none; color: rgb(3,32,40); } </style> <a href="#${this._target}"><slot></slot></a>
</template>

и:

<template id="tab-content"> <style> :host { display: none; padding: 20px; width: 100%; background-color: rgb(255,212,201); } :host-context(.active){ display: block; } </style> <div><slot></slot></div>
</template>

Для TabNavigationItem это будет: В конструкторе каждого класса я сохраню свойство template.

this.template = document.getElementById('tab-nav');

a для TabContentItem:

this.template = document.getElementById('tab-content');

В метод render() каждому из этих классов я добавлю следующий код, предварительно удалив запись .innerHTML:

const content = this.template.content.cloneNode(true); this.shadowRoot.appendChild(content);

Получившийся код можно посмотреть тут

Это плавно переводит нас к теме: В этом примере оба шаблона указаны в html, что выглядит громозким и не есть гуд.

HTML импорты

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

Общая схема видна на изображении:

.

Для того чтобы реализовать импорты был добавлен новый тип в HTML link types (значения атрибута rel).

Слово import, указанное в значение атрибута rel элемента <link> собственно и создает ссылку к импортируемому ресурсу (дефолтным типом ресурса является text/html).

У элемента <link> может присутствовать атрибут async.

Расширения, предлагаемые черновиком спецификации предлагаются в АПИ HTMLLinkElement: добавляется свойство import, доступное только для чтения и содержащее импортируемый документ.

Свойство может содержать значение null в двух случаях: когда <link> не представляет import или <link> не находится в документе.

В спецификации отдельно указано что один и тот же объект должен будет возвращаться всегда.

В контексте импортов, есть так называемый мастер-документ (master document), которым является тот документ, который импортирует ресурсы одновременно не являясь при этом чьим либо импортируемым ресурсом.

Так, если Content Security Header Field поставлен в значение импорта, браузер должен принудительно исполнять политику именно мастер-документа к импортируемому документу. ContentSecurityPolicy такого документа должна ограничивать все импорты.

На практике

В ней я создам два файла, в которые я перенесу разметку компоненты. Для компонента таб, я создаю папку templates.

<!--templates/tab-content.html--> <template id="tab-content"> <style> :host { display: none; padding: 20px; width: 100%; background-color: rgb(255,212,201); } :host-context(.active){ display: block; } </style> <div><slot></slot></div> </template> <!--templates/tab-nav.html--> <template id="tab-nav"> <style> :host{ padding: 10px; background-color: rgb(81,180,186); transition: background-color 1s; text-align: center; } :host-context(.active) { background-color: rgb(93, 209, 216); } a{ text-decoration: none; color: rgb(3,32,40); } </style> <a href="#${this._target}"><slot></slot></a> </template>

В <head> файла index.html я импортирую шаблоны:

<link rel="import" href="templates/tab-nav.html" id="tab-nav"> <link rel="import" href="templates/tab-content.html" id="tab-content">

Элементам <link> я добавляю id атрибуты, так как мне понадобится обращаться к ним из js.
Теперь в конструкторах классов TabNavigationItem и TabContentItem для получения документа шаблона мне достаточно будет найти соответствующий элемент <link> и обратится к его свойству import, после чего поиск шаблона я буду выполнять уже в импортируемом документе:

class TabNavigationItem extends HTMLElement { constructor() { super(); this._target = null; this.attachShadow({mode: 'open'}); const templateImport = document.getElementById('tab-nav').import; this.template = templateImport.getElementById('tab-nav'); } //... } class TabContentItem extends HTMLElement { constructor() { super(); this._target = null; this.attachShadow({mode: 'open'}); const templateImport = document.getElementById('tab-content').import; this.template = templateImport.getElementById('tab-content'); } //... }

Финальную версию можно взять тут.

О поддержке

Поддержка HTML templates: Edge c 16, Firefox c 59, Chrome c 49, Safari c 11.
С поддержкой импортов печальнее: Chrome c 49.
Потому примеры из этой статьи можно посмотреть только в последних Chrome.

Существуют полифилы:

Webcomponents
Polymer-project

Почтитать подробнее о шаблонах и импортах:

HTML спецификация
HTML5 спецификация
HTML Imports черновик спецификации

На этом все, спасибо за внимание,
Таня


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

[Перевод] Учёные вырастили универсальные стволовые клетки при помощи CRISPR инженерии

Клетки сердечной мышцы человека, полученные из новых универсальных стволовых клеток Учёные из University of California San Francisco впервые вырастили универсальные стволовые клетки, используя технологию редактирования генов CRISPR в целях получения плюрипотентных стволовых клеток, которые могут быть трансплантированы любому пациенту, не ...

[Перевод] Шесть историй, как код переписали с нуля

Новый взгляд на извечный вопрос: следует ли переписывать приложение с нуля или это «самая худшая стратегическая ошибка, которую может сделать разработчик программного обеспечения»? Оказывается, при работе со зрелой кодовой базой есть более двух вариантов ответа. «Исходный код словно заржавел!» — Джоэл ...