Понятия
lit-html использует некоторые уникальные свойства шаблонных литералов JavaScript и элементов HTML <template>, чтобы работать и обеспечивать высокую производительность. Поэтому сначала полезно разобраться в них.
Тегированные шаблонные литералы
Шаблонный литерал JavaScript — это строковый литерал, в который можно встраивать выражения JavaScript:
`My name is ${name}.`
В литерале вместо кавычек используются обратные кавычки; он может занимать несколько строк. Внутри ${} может находиться любое выражение JavaScript.
Тегированный шаблонный литерал предваряется специальной функцией-тегом шаблона:
let name = 'Monica';
tag`My name is ${name}.`
Теги — это функции, которые принимают строковые фрагменты шаблона и значения встроенных выражений, а затем возвращают новое значение. Это может быть значение любого типа, а не только строка. lit-html возвращает объект, представляющий шаблон и называемый TemplateResult.
Ключевая особенность тегов шаблонов, которую lit-html использует для ускорения обновлений, заключается в том, что объект, содержащий строковые фрагменты шаблона, в точности одинаков при каждом вызове тега для конкретного шаблона.
Это означает, что строки можно использовать в качестве ключа кэша: lit-html подготавливает шаблон только один раз, при его первом отображении, а при последующих обновлениях этот этап пропускается.
Элементы template HTML
Элемент <template> содержит неактивный фрагмент DOM. Внутри содержимого шаблона скрипты не выполняются, изображения не загружаются, пользовательские элементы не обновляются и так далее. Содержимое можно эффективно клонировать. Элементы template обычно используются, чтобы указать парсеру HTML, что раздел документа не нужно создавать при разборе и что позднее им будет управлять код; однако элементы template также можно создавать императивно с помощью createElement и innerHTML.
lit-html создаёт элементы HTML <template> из тегированных шаблонных литералов, а затем клонирует их для создания нового DOM.
Создание шаблона
При первом отображении конкретного шаблона lit-html где-либо в приложении выполняет однократную настройку, чтобы создать HTML-шаблон. Он объединяет все литеральные части со специальным заполнителем, похожим на "{{}}", затем создаёт <template> и присваивает его innerHTML полученный результат.
Если начать с такого шаблона:
let header = (title) => html`<h1>${title}</h1>`;
lit-html сгенерирует следующий HTML:
<h1>{{}}</h1>
И создаст на его основе <template>.
Затем lit-html обходит DOM шаблона, извлекает заполнители и записывает их расположение. В итоговом шаблоне заполнителей нет:
<h1></h1>
lit-html хранит вспомогательную таблицу с расположением выражений:
[{type: 'node', index: 1}]
Отображение шаблона
render() принимает TemplateResult и отображает его в контейнере DOM. При первоначальном отображении он клонирует шаблон, а затем обходит его, используя сохранённые позиции заполнителей, чтобы создать объекты Part.
Part — это «пустое место» в DOM, куда можно подставлять значения. В lit-html есть подклассы Part для каждого типа привязки: NodePart для привязок текстового содержимого, AttributePart для привязок атрибутов и так далее. Объекты Part, контейнер и шаблон, на основе которого они созданы, объединяются в объект под названием TemplateInstance.
Функциональный подход
lit-html идеально подходит для функционального подхода к описанию пользовательских интерфейсов. Если рассматривать интерфейс как функцию от данных, обычно записываемую как UI = f(data), можно создавать шаблоны lit-html, которые точно этому соответствуют:
let ui = (data) => html`...${data}...`;
Такую функцию можно вызывать при каждом изменении данных, и вызов обходится чрезвычайно дёшево. Единственное, что lit-html делает с тегом html, — передаёт аргументы шаблонам.
При отображении результата lit-html обновляет только те выражения, значения которых изменились после предыдущего отображения.
В результате получается простая в написании и понятная модель: старайтесь всегда описывать пользовательский интерфейс как простую функцию от данных, от которых он зависит, и избегайте кэширования промежуточного состояния и ручного управления DOM. В большинстве случаев lit-html будет достаточно быстрым даже при самом простом описании интерфейса.
Модули JavaScript
Почему lit-html распространяется в виде модулей JavaScript, а не UMD/CJS/AMD?
До появления модулей в браузерах не было стандартного способа импортировать код из кода, поэтому требовались пользовательские загрузчики модулей или сборщики. Отсутствие стандарта привело к появлению множества конкурирующих форматов. Библиотеки часто публикуются в нескольких форматах для поддержки пользователей разных инструментов, но это создаёт проблемы, когда от общей библиотеки зависят многие другие промежуточные библиотеки. Если одни из них загружают формат A, другие — формат B, а третьи — формат C, загружается несколько копий, что увеличивает объём кода, снижает производительность и иногда приводит к трудноуловимым ошибкам.
Единственное надёжное решение — иметь одну каноническую версию библиотеки, которую импортируют все остальные библиотеки. Поддержка модулей уже внедряется в браузеры, а инструменты хорошо их поддерживают, поэтому логично выбрать именно этот формат.
В настоящее время браузер принимает модули, указанные с помощью полного или относительного пути (пути, начинающегося с /, ./ или ../). Для удобства многие разработчики предпочитают импортировать модули по имени (также известные как спецификаторы модулей в стиле Node.js). Поскольку браузер пока не поддерживает такой способ, необходимо использовать инструменты, которые преобразуют эти спецификаторы в пути, подходящие для браузера. Сведения о серверах разработки и инструментах сборки, которые могут выполнить это преобразование, см. в разделе Инструменты:
// Node-style module import:
import {html, render} from 'lit-html';
// Browser-ready module import
import {html, render} from '../node_modules/lit-html/lit-html.js';
Дополнительные сведения о модулях JavaScript:
Использование модулей JavaScript в интернете в документации Web Fundamentals.
Справка по оператору import на MDN.
© Google LLC
Licensed under the Creative Commons Attribution 3.0 Unported License.
https://lit.dev/docs/v1/lit-html/concepts/