Встроенные директивы
Директивы — это функции, которые расширяют Lit, настраивая способ отображения выражения. Lit включает ряд встроенных директив для решения различных задач отображения:
| Директива | Описание |
|---|---|
Стилизация | |
Назначает элементу список классов на основе объекта. |
|
Задаёт элементу список свойств стиля на основе объекта. |
|
Циклы и условия | |
| Отображает один из двух шаблонов в зависимости от условия. | |
| Отображает один из нескольких шаблонов в зависимости от значения ключа. | |
| Преобразует итерируемый объект с помощью функции. | |
| Отображает значения из итерируемого объекта в DOM, при необходимости используя ключи для сравнения данных и обеспечения стабильности DOM. | |
| Вставляет значение-разделитель между значениями итерируемого объекта. | |
| Создаёт последовательность итерируемых чисел; полезно для выполнения цикла заданное число раз. | |
| Задаёт атрибут, если значение определено, и удаляет атрибут, если оно не определено. | |
Кэширование и обнаружение изменений | |
| Кэширует отображённый DOM при смене шаблонов, а не удаляет его. | |
| Связывает отображаемое значение с уникальным ключом и заставляет DOM перерисоваться при изменении ключа. | |
| Повторно вычисляет шаблон, только если меняется одна из его зависимостей. | |
| Задаёт атрибут или свойство, если оно отличается от текущего значения в DOM, а не от значения при последнем отображении. | |
Обращение к отображённому DOM | |
| Получает ссылку на элемент, отображённый в шаблоне. | |
Отображение специальных значений | |
Отображает содержимое элемента |
|
| Отображает строку как HTML, а не как текст. | |
| Отображает строку как SVG, а не как текст. | |
Асинхронное отображение | |
| Отображает содержимое-заполнитель, пока не будет выполнен один или несколько промисов. | |
Добавляет значения из |
|
Отображает последнее значение из |
|
Добавляйте в сборку только то, что используете. Эти директивы называются «встроенными», потому что входят в пакет Lit. Однако каждая директива является отдельным модулем, поэтому в сборку приложения попадают только импортированные директивы.
Вы также можете создавать собственные директивы. Дополнительную информацию см. в разделе Пользовательские директивы.
Стилизация
classMap
Назначает элементу список классов на основе объекта.
| Импорт | import {classMap} from 'lit/directives/class-map.js'; |
| Сигнатура | classMap(classInfo: {[name: string]: string | boolean | number}) |
| Допустимое место использования | Выражение атрибута |
Директива classMap использует API element.classList для эффективного добавления и удаления классов элемента на основе переданного пользователем объекта. Каждый ключ объекта рассматривается как имя класса. Если связанное с ключом значение является истинным, этот класс добавляется элементу. При последующих отображениях ранее заданные классы, значения которых ложны или которых больше нет в объекте, удаляются.
@customElement('my-element')
class MyElement extends LitElement {
@property({type: Boolean})
enabled = false;
render() {
const classes = { enabled: this.enabled, hidden: false };
return html`<div class=${classMap(classes)}>Classy text</div>`;
}
}
class MyElement extends LitElement {
static properties = {
enabled: {type: Boolean},
};
constructor() {
super();
this.enabled = false;
}
render() {
const classes = { enabled: this.enabled, hidden: false };
return html`<div class=${classMap(classes)}>Classy text</div>`;
}
}
customElements.define('my-element', MyElement);Директива classMap должна быть единственным выражением в атрибуте class, но её можно сочетать со статическими значениями:
html`<div class="my-widget ${classMap(dynamicClasses)}">Static and dynamic</div>`;
Подробнее изучите classMap в песочнице.
styleMap
Задаёт элементу список свойств стиля на основе объекта.
| Импорт | import {styleMap} from 'lit/directives/style-map.js'; |
| Сигнатура | styleMap(styleInfo: {[name: string]: string | undefined | null}) |
| Допустимое место использования | Выражение атрибута |
Директива styleMap использует API element.style для эффективного добавления и удаления встроенных стилей элемента на основе переданного пользователем объекта. Каждый ключ объекта рассматривается как имя свойства стиля, а значение — как значение этого свойства. При последующих отображениях ранее заданные свойства стиля со значением undefined или null удаляются (устанавливаются в null).
@customElement('my-element')
class MyElement extends LitElement {
@property({type: Boolean})
enabled = false;
render() {
const styles = { backgroundColor: this.enabled ? 'blue' : 'gray', color: 'white' };
return html`<p style=${styleMap(styles)}>Hello style!</p>`;
}
}
class MyElement extends LitElement {
static properties = {
enabled: {type: Boolean},
};
constructor() {
super();
this.enabled = false;
}
render() {
const styles = { backgroundColor: this.enabled ? 'blue' : 'gray', color: 'white' };
return html`<p style=${styleMap(styles)}>Hello style!</p>`;
}
}
customElements.define('my-element', MyElement);Для CSS-свойств, содержащих дефисы, можно использовать эквивалент в формате camelCase или заключить имя свойства в кавычки. Например, CSS-свойство font-family можно записать как fontFamily или 'font-family':
{ fontFamily: 'roboto' }
{ 'font-family': 'roboto' }
Ссылайтесь на пользовательские свойства CSS, например --custom-color, заключая всё имя свойства в кавычки:
{ '--custom-color': 'steelblue' }
Директива styleMap должна быть единственным выражением в атрибуте style, но её можно сочетать со статическими значениями:
html`<p style="color: white; ${styleMap(moreStyles)}">More styles!</p>`;
Подробнее изучите styleMap в песочнице.
Циклы и условия
when
Отображает один из двух шаблонов в зависимости от условия.
| Импорт | import {when} from 'lit/directives/when.js'; |
| Сигнатура | when<T, F>( condition: boolean, trueCase: () => T, falseCase?: () => F ) |
| Допустимое место использования | Любое |
Если condition равно true, возвращает результат вызова trueCase(); в противном случае возвращает результат вызова falseCase(), если falseCase задано.
Это вспомогательная обёртка для тернарного выражения, позволяющая удобнее записывать встроенное условие без ветви else.
class MyElement extends LitElement {
render() {
return html`
${when(this.user, () => html`User: ${this.user.username}`, () => html`Sign In...`)}
`;
}
}
choose
Выбирает и вычисляет функцию шаблона из списка вариантов, сопоставляя заданное value с одним из вариантов.
| Импорт | import {choose} from 'lit/directives/choose.js'; |
| Сигнатура | choose<T, V>( value: T, cases: Array<[T, () => V]>, defaultCase?: () => V ) |
| Допустимое место использования | Любое |
Варианты задаются в виде [caseValue, func]. value сопоставляется с caseValue по строгому равенству. Выбирается первое совпадение. Значения вариантов могут иметь любой тип, включая примитивы, объекты и символы.
Это похоже на оператор switch, но используется как выражение и не поддерживает проваливание.
class MyElement extends LitElement {
render() {
return html`
${choose(this.section, [
['home', () => html`<h1>Home</h1>`],
['about', () => html`<h1>About</h1>`]
],
() => html`<h1>Error</h1>`)}
`;
}
}
map
Возвращает итерируемый объект, содержащий результат вызова f(value) для каждого значения в items.
| Импорт | import {map} from 'lit/directives/map.js'; |
| Сигнатура | map<T>( items: Iterable<T> | undefined, f: (value: T, index: number) => unknown ) |
| Допустимое место использования | Любое |
map() — это простая обёртка для цикла for/of, упрощающая работу с итерируемыми объектами в выражениях. map() всегда обновляет созданный DOM на месте — она не выполняет сравнение и не перемещает элементы DOM. Если это необходимо, используйте repeat. map() меньше и быстрее, чем repeat(), поэтому, если сравнение и стабильность DOM не нужны, предпочтительнее использовать map().
class MyElement extends LitElement {
render() {
return html`
<ul>
${map(items, (i) => html`<li>${i}</li>`)}
</ul>
`;
}
}
repeat
Отображает значения из итерируемого объекта в DOM, при необходимости используя ключи для сравнения данных и обеспечения стабильности DOM.
| Импорт | import {repeat} from 'lit/directives/repeat.js'; |
| Сигнатура | repeat(items: Iterable<T>, keyfn: KeyFn<T>, template: ItemTemplate<T>) repeat(items: Iterable<T>, template: ItemTemplate<T>) type KeyFn<T> = (item: T, index: number) => unknown; type ItemTemplate<T> = (item: T, index: number) => unknown; |
| Допустимое место использования | Дочернее выражение |
Повторяет последовательность значений (обычно TemplateResults), созданных на основе итерируемого объекта, и эффективно обновляет эти элементы при изменении итерируемого объекта. Если задана функция keyFn, при обновлениях сохраняется связь ключей с DOM: созданный DOM при необходимости перемещается. Как правило, это самый эффективный способ использования repeat, поскольку при вставке и удалении выполняется минимум лишней работы.
Если вы не используете функцию ключа, рассмотрите возможность использования map().
@customElement('my-element')
class MyElement extends LitElement {
@property()
items: Array<{id: number, name: string}> = [];
render() {
return html`
<ul>
${repeat(this.items, (item) => item.id, (item, index) => html`
<li>${index}: ${item.name}</li>`)}
</ul>
`;
}
}
class MyElement extends LitElement {
static properties = {
items: {},
};
constructor() {
super();
this.items = [];
}
render() {
return html`
<ul>
${repeat(this.items, (item) => item.id, (item, index) => html`
<li>${index}: ${item.name}</li>`)}
</ul>
`;
}
}
customElements.define('my-element', MyElement);Если keyFn не задана, repeat будет работать аналогично простому отображению элементов в значения, а DOM будет повторно использоваться для потенциально других элементов.
Обсуждение того, когда использовать repeat, а когда стандартные средства управления потоком JavaScript, см. в разделе Когда использовать map или repeat.
Подробнее изучите repeat в песочнице.
join
Возвращает итерируемый объект, в котором значения из items чередуются со значением joiner.
| Импорт | import {join} from 'lit/directives/join.js'; |
| Сигнатура | join<I, J>( items: Iterable<I> | undefined, joiner: J ): Iterable<I | J>; join<I, J>( items: Iterable<I> | undefined, joiner: (index: number) => J ): Iterable<I | J>; |
| Допустимое место использования | Любое |
class MyElement extends LitElement {
render() {
return html`
${join(
map(menuItems, (i) => html`<a href=${i.href}>${i.label}</a>`),
html`<span class="separator">|</span>`
)}
`;
}
}
range
Возвращает итерируемый объект с целыми числами от start до end (не включая это значение), с шагом step.
| Импорт | import {range} from 'lit/directives/range.js'; |
| Сигнатура | range(end: number): Iterable<number>; range( start: number, end: number, step?: number ): Iterable<number>; |
| Допустимое место использования | Любое |
class MyElement extends LitElement {
render() {
return html`
${map(range(8), (i) => html`${i + 1}`)}
`;
}
}
ifDefined
Задаёт атрибут, если значение определено, и удаляет атрибут, если оно не определено.
| Импорт | import {ifDefined} from 'lit/directives/if-defined.js'; |
| Сигнатура | ifDefined(value: unknown) |
| Допустимое место использования | Выражение атрибута |
Для AttributeParts задаёт атрибут, если значение определено, и удаляет его, если значение не определено (undefined или null). Для других типов частей директива ничего не делает.
Если в одном значении атрибута содержится несколько выражений, атрибут будет удалён, если любое выражение использует ifDefined и вычисляется как undefined/null. Это особенно полезно при задании URL-атрибутов: если необходимые части URL не определены, атрибут не следует задавать, чтобы избежать ошибок 404.
@customElement('my-element')
class MyElement extends LitElement {
@property()
filename: string | undefined = undefined;
@property()
size: string | undefined = undefined;
render() {
// src attribute not rendered if either size or filename are undefined
return html`<img src="/images/${ifDefined(this.size)}/${ifDefined(this.filename)}">`;
}
}
class MyElement extends LitElement {
static properties = {
filename: {},
size: {},
};
constructor() {
super();
this.filename = undefined;
this.size = undefined;
}
render() {
// src attribute not rendered if either size or filename are undefined
return html`<img src="/images/${ifDefined(this.size)}/${ifDefined(this.filename)}">`;
}
}
customElements.define('my-element', MyEleent);Подробнее изучите ifDefined в песочнице.
Кэширование и обнаружение изменений
cache
Кэширует отображённый DOM при смене шаблонов, а не удаляет его. Эту директиву можно использовать для повышения производительности отображения при частом переключении между большими шаблонами.
| Импорт | import {cache} from 'lit/directives/cache.js'; |
| Сигнатура | cache(value: TemplateResult|unknown) |
| Допустимое место использования | Дочернее выражение |
Когда переданное в cache значение меняется между одним или несколькими TemplateResult, узлы DOM, отображённые для соответствующего шаблона, кэшируются, пока не используются. При смене шаблона директива кэширует текущие узлы DOM перед переключением на новое значение и восстанавливает их из кэша при возвращении к ранее отображённому значению, вместо того чтобы создавать узлы DOM заново.
const detailView = (data) => html`<div>...</div>`;
const summaryView = (data) => html`<div>...</div>`;
@customElement('my-element')
class MyElement extends LitElement {
@property()
data = {showDetails: true, /*...*/ };
render() {
return html`${cache(this.data.showDetails
? detailView(this.data)
: summaryView(this.data)
)}`;
}
}
const detailView = (data) => html`<div>...</div>`;
const summaryView = (data) => html`<div>...</div>`;
class MyElement extends LitElement {
static properties = {
data: {},
};
constructor() {
super();
this.data = {showDetails: true, /*...*/ };
}
render() {
return html`${cache(this.data.showDetails
? detailView(this.data)
: summaryView(this.data)
)}`;
}
}
customElements.define('my-element', MyElement);При повторном отображении шаблона Lit обновляет только изменённые части: он не создаёт и не удаляет больше элементов DOM, чем необходимо. Но при переключении с одного шаблона на другой Lit удаляет старый DOM и отображает новое дерево DOM.
Директива cache кэширует созданный DOM для заданного выражения и входного шаблона. В примере выше она кэширует DOM для обоих шаблонов: summaryView и detailView. При переключении между представлениями Lit подставляет кэшированную версию нового представления и обновляет её последними данными. Это может повысить производительность отображения, если представления часто переключаются.
Подробнее изучите cache в песочнице.
keyed
Связывает отображаемое значение с уникальным ключом. При изменении ключа предыдущий DOM удаляется и очищается перед отображением следующего значения, даже если значение — например, шаблон — не изменилось.
| Импорт | import {keyed} from 'lit/directives/keyed.js'; |
| Сигнатура | keyed(key: unknown, value: unknown) |
| Допустимое место использования | Любое выражение |
keyed полезна при отображении элементов с состоянием, когда нужно гарантировать сброс всего состояния элемента при изменении критически важных данных. По сути, она отключает используемую по умолчанию стратегию повторного использования DOM в Lit.
keyed также полезна в некоторых сценариях анимации, когда для анимации «появления» или «исчезновения» требуется создать новый элемент.
@customElement('my-element')
class MyElement extends LitElement {
@property()
userId: string = '';
render() {
return html`
<div>
${keyed(this.userId, html`<user-card .userId=${this.userId}></user-card>`)}
</div>`;
}
}
class MyElement extends LitElement {
static properties = {
userId: {},
};
constructor() {
super();
this.userId = '';
}
render() {
return html`
<div>
${keyed(this.userId, html`<user-card .userId=${this.userId}></user-card>`)}
</div>`;
}
}
customElements.define('my-element', MyElement);guard
Повторно вычисляет шаблон, только если меняется одна из его зависимостей, чтобы повысить производительность отображения и избежать ненужной работы.
| Импорт | import {guard} from 'lit/directives/guard.js'; |
| Сигнатура | guard(dependencies: unknown[], valueFn: () => unknown) |
| Допустимое место использования | Любое выражение |
Отображает значение, возвращённое valueFn, и повторно вычисляет valueFn только при изменении идентичности одной из зависимостей.
Где:
-
dependencies— массив значений, за изменениями которых нужно следить. -
valueFn— функция, возвращающая отображаемое значение.
guard полезна при работе с неизменяемыми данными: она позволяет отложить затратные операции до обновления данных.
@customElement('my-element')
class MyElement extends LitElement {
@property()
value: string = '';
render() {
return html`
<div>
${guard([this.value], () => calculateSHA(this.value))}
</div>`;
}
}
class MyElement extends LitElement {
static properties = {
value: {},
};
constructor() {
super();
this.value = '';
}
render() {
return html`
<div>
${guard([this.value], () => calculateSHA(this.value))}
</div>`;
}
}
customElements.define('my-element', MyElement);В этом случае затратная функция calculateSHA запускается только при изменении свойства value.
Подробнее изучите guard в песочнице.
live
Задаёт атрибут или свойство, если оно отличается от текущего значения в DOM, а не от значения при последнем отображении.
| Импорт | import {live} from 'lit/directives/live.js'; |
| Сигнатура | live(value: unknown) |
| Допустимое место использования | Выражение атрибута или свойства |
При определении необходимости обновить значение сравнивает значение выражения с текущим значением в DOM, а не использует поведение Lit по умолчанию, при котором сравнивается последнее заданное значение.
Это полезно в случаях, когда значение в DOM может измениться независимо от Lit. Например, при использовании выражения для задания свойства <input> элемента, свойства value, текста редактируемого элемента или пользовательского элемента, изменяющего собственные свойства или атрибуты.
В этих случаях, если значение в DOM меняется, а значение, заданное через выражение Lit, — нет, Lit не узнает об изменении и оставит значение DOM без изменений. Если это не то, что вам нужно, и вы хотите всегда перезаписывать значение DOM связанным значением, используйте директиву live().
@customElement('my-element')
class MyElement extends LitElement {
@property()
data = {value: 'test'};
render() {
return html`<input .value=${live(this.data.value)}>`;
}
}
class MyElement extends LitElement {
static properties = {
data: {},
};
constructor() {
super();
this.data = {value: 'test'};
}
render() {
return html`<input .value=${live(this.data.value)}>`;
}
}
customElements.define('my-element', MyElement);live() выполняет проверку строгого равенства с текущим значением DOM и ничего не делает, если новое значение совпадает с текущим. Это означает, что live() не следует использовать, если выражение приводит к преобразованию типа. Если вы используете live() с выражением атрибута, передавайте только строки, иначе выражение будет обновляться при каждом отображении.
Подробнее изучите live в песочнице.
Отображение специальных значений
templateContent
Отображает содержимое элемента <template>.
| Импорт | import {templateContent} from 'lit/directives/template-content.js'; |
| Сигнатура | templateContent(templateElement: HTMLTemplateElement) |
| Допустимое место использования | Дочернее выражение |
Шаблоны Lit записываются на JavaScript, что позволяет включать в них выражения JavaScript и делать их динамическими. Если в шаблон Lit нужно включить статический HTML-элемент <template>, используйте директиву templateContent, чтобы клонировать содержимое шаблона и включить его в шаблон Lit. Если ссылка на элемент шаблона не меняется между отображениями, при последующих отображениях никаких действий не выполняется.
Обратите внимание: содержимое шаблона должно контролироваться разработчиком и не должно создаваться из недоверенной строки. К недоверенному содержимому относятся, например, параметры строки запроса и значения, полученные от пользователей. Отображение недоверенных шаблонов с помощью этой директивы может привести к уязвимостям, связанным с межсайтовым скриптингом (XSS).
const templateEl = document.querySelector('template#myContent') as HTMLTemplateElement;
@customElement('my-element')
class MyElement extends LitElement {
render() {
return html`
Here's some content from a template element:
${templateContent(templateEl)}`;
}
}
const templateEl = document.querySelector('template#myContent');
class MyElement extends LitElement {
render() {
return html`
Here's some content from a template element:
${templateContent(templateEl)}`;
}
}
customElements.define('my-element', MyElement);Подробнее изучите templateContent в песочнице.
unsafeHTML
Отображает строку как HTML, а не как текст.
| Импорт | import {unsafeHTML} from 'lit/directives/unsafe-html.js'; |
| Сигнатура | unsafeHTML(value: string | typeof nothing | typeof noChange) |
| Допустимое место использования | Дочернее выражение |
Важная особенность синтаксиса шаблонов Lit заключается в том, что HTML разбирается только из строковых литералов шаблонов. Поскольку такие литералы можно создавать только в доверенных файлах скриптов, это служит естественной защитой от XSS-атак, внедряющих недоверенный HTML. Однако бывают случаи, когда в шаблоне Lit нужно отобразить HTML, полученный не из файла скрипта, например доверенное содержимое HTML, загруженное из базы данных. Директива unsafeHTML разбирает такую строку как HTML и отображает её в шаблоне Lit.
Обратите внимание: строка, передаваемая в unsafeHTML, должна контролироваться разработчиком и не должна содержать недоверенное содержимое. К недоверенному содержимому относятся, например, параметры строки запроса и значения, полученные от пользователей. Отображение недоверенного содержимого с помощью этой директивы может привести к уязвимостям, связанным с межсайтовым скриптингом (XSS).
const markup = '<h3>Some HTML to render.</h3>';
@customElement('my-element')
class MyElement extends LitElement {
render() {
return html`
Look out, potentially unsafe HTML ahead:
${unsafeHTML(markup)}
`;
}
}
const markup = '<h3>Some HTML to render.</h3>';
class MyElement extends LitElement {
render() {
return html`
Look out, potentially unsafe HTML ahead:
${unsafeHTML(markup)}
`;
}
}
customElements.define('my-element', MyElement);Подробнее изучите unsafeHTML в песочнице.
unsafeSVG
Отображает строку как SVG, а не как текст.
| Импорт | import {unsafeSVG} from 'lit/directives/unsafe-svg.js'; |
| Сигнатура | unsafeSVG(value: string | typeof nothing | typeof noChange) |
| Допустимое место использования | Дочернее выражение |
Как и в случае с unsafeHTML, бывают случаи, когда в шаблоне Lit нужно отобразить содержимое SVG, полученное не из файла скрипта, например доверенное содержимое SVG, загруженное из базы данных. Директива unsafeSVG разбирает такую строку как SVG и отображает её в шаблоне Lit.
Обратите внимание: строка, передаваемая в unsafeSVG, должна контролироваться разработчиком и не должна содержать недоверенное содержимое. К недоверенному содержимому относятся, например, параметры строки запроса и значения, полученные от пользователей. Отображение недоверенного содержимого с помощью этой директивы может привести к уязвимостям, связанным с межсайтовым скриптингом (XSS).
const svg = '<circle cx="50" cy="50" r="40" fill="red" />';
@customElement('my-element')
class MyElement extends LitElement {
render() {
return html`
Look out, potentially unsafe SVG ahead:
<svg width="40" height="40" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg" version="1.1">
${unsafeSVG(svg)}
</svg> `;
}
}
const svg = '<circle cx="50" cy="50" r="40" fill="red" />';
class MyElement extends LitElement {
render() {
return html`
Look out, potentially unsafe SVG ahead:
<svg width="40" height="40" viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg" version="1.1">
${unsafeSVG(svg)}
</svg> `;
}
}
customElements.define('my-element', MyElement);Подробнее изучите unsafeSVG в песочнице.
Обращение к отображённому DOM
ref
Получает ссылку на элемент, отображённый в DOM.
| Импорт | import {ref} from 'lit/directives/ref.js'; |
| Сигнатура | ref(refOrCallback: RefOrCallback) |
| Допустимое место использования | Выражение элемента |
Хотя большую часть операций с DOM в Lit можно выполнять декларативно с помощью шаблонов, в сложных случаях может потребоваться получить ссылку на элемент, отображённый в шаблоне, и управлять им императивно. Например, это может быть полезно, чтобы установить фокус на элемент формы или вызвать библиотеку для императивного управления DOM для элемента-контейнера.
Если поместить директиву ref на элемент шаблона, после отображения она получит ссылку на этот элемент. Ссылку на элемент можно получить одним из двух способов: передать объект Ref или передать функцию обратного вызова.
Объект Ref служит контейнером для ссылки на элемент. Его можно создать с помощью вспомогательного метода createRef из модуля ref. После отображения свойству value объекта Ref будет присвоен элемент. К нему можно обратиться на этапах жизненного цикла после отображения, например в updated.
@customElement('my-element')
class MyElement extends LitElement {
inputRef: Ref<HTMLInputElement> = createRef();
render() {
// Passing ref directive a Ref object that will hold the element in .value
return html`<input ${ref(this.inputRef)}>`;
}
firstUpdated() {
const input = this.inputRef.value!;
input.focus();
}
}
class MyElement extends LitElement {
inputRef = createRef();
render() {
// Passing ref directive a Ref object that will hold the element in .value
return html`<input ${ref(this.inputRef)}>`;
}
firstUpdated() {
const input = this.inputRef.value!;
input.focus();
}
}
customElements.define('my-element', MyElement);Директиве ref также можно передать функцию обратного вызова ref. Она будет вызываться каждый раз, когда меняется связанный с ней элемент. Если при последующем отображении функция обратного вызова ref будет привязана к другой позиции элемента или удалена, сначала она будет вызвана с аргументом undefined, а затем ещё раз — с новым элементом, к которому она привязана (если он есть). Обратите внимание: в LitElement функция обратного вызова автоматически вызывается в контексте главного элемента.
@customElement('my-element')
class MyElement extends LitElement {
render() {
// Passing a change callback to ref directive
return html`<input ${ref(this.inputChanged)}>`;
}
inputChanged(input?: HTMLInputElement) {
input?.focus();
}
}
class MyElement extends LitElement {
render() {
// Passing a change callback to ref directive
return html`<input ${ref(this.inputChanged)}>`;
}
inputChanged(input) {
input?.focus();
}
}
customElements.define('my-element', MyElement);Подробнее изучите ref в песочнице.
Асинхронное отображение
until
Отображает содержимое-заполнитель, пока не будет выполнен один или несколько промисов.
| Импорт | import {until} from 'lit/directives/until.js'; |
| Сигнатура | until(...values: unknown[]) |
| Допустимое место использования | Любое выражение |
Принимает последовательность значений, в том числе промисы. Значения отображаются в порядке приоритета: первый аргумент имеет наивысший приоритет, а последний — наименьший. Если значение является промисом, до его выполнения отображается значение с меньшим приоритетом.
Приоритет значений позволяет создавать содержимое-заполнитель для асинхронных данных. Например, промис с ещё не полученным содержимым можно передать первым аргументом (с наивысшим приоритетом), а шаблон индикатора загрузки, не являющийся промисом, — вторым (с более низким приоритетом). Индикатор загрузки отображается немедленно, а основное содержимое — после выполнения промиса.
@customElement('my-element')
class MyElement extends LitElement {
@state()
private content = fetch('./content.txt').then(r => r.text());
render() {
return html`${until(this.content, html`<span>Loading...</span>`)}`;
}
}
class MyElement extends LitElement {
static properties = {
content: {state: true},
};
constructor() {
super();
this.content = fetch('./content.txt').then(r => r.text());
}
render() {
return html`${until(this.content, html`<span>Loading...</span>`)}`;
}
}
customElements.define('my-element', MyElement);Подробнее изучите until в песочнице.
asyncAppend
Добавляет значения из AsyncIterable в DOM по мере их выдачи.
| Импорт | import {asyncAppend} from 'lit/directives/async-append.js'; |
| Сигнатура | asyncAppend( iterable: AsyncIterable<I>, mapper?: (item: I, index?: number) => unknown ) |
| Допустимое место использования | Выражение в дочернем элементе |
asyncAppend отображает значения асинхронного итерируемого объекта, добавляя каждое новое значение после предыдущего. Обратите внимание, что асинхронные генераторы также реализуют протокол асинхронного итерируемого объекта, поэтому их можно обрабатывать с помощью asyncAppend.
async function *tossCoins(count: number) {
for (let i=0; i<count; i++) {
yield Math.random() > 0.5 ? 'Heads' : 'Tails';
await new Promise((r) => setTimeout(r, 1000));
}
}
@customElement('my-element')
class MyElement extends LitElement {
@state()
private tosses = tossCoins(10);
render() {
return html`
<ul>${asyncAppend(this.tosses, (v: string) => html`<li>${v}</li>`)}</ul>`;
}
}
async function *tossCoins(count) {
for (let i=0; i<count; i++) {
yield Math.random() > 0.5 ? 'Heads' : 'Tails';
await new Promise((r) => setTimeout(r, 1000));
}
}
class MyElement extends LitElement {
static properties = {
tosses: {state: true},
};
constructor() {
super();
this.tosses = tossCoins(10);
}
render() {
return html`
<ul>${asyncAppend(this.tosses, (v) => html`<li>${v}</li>`)}</ul>`;
}
}
customElements.define('my-element', MyElement);Подробнее изучите asyncAppend в песочнице.
asyncReplace
Отображает в DOM последнее значение, полученное из AsyncIterable.
| Импорт | import {asyncReplace} from 'lit/directives/async-replace.js'; |
| Сигнатура | asyncReplace( iterable: AsyncIterable<I>, mapper?: (item: I, index?: number) => unknown ) |
| Допустимое место использования | Любое выражение |
Подобно asyncAppend, asyncReplace отображает значения асинхронного итерируемого объекта, заменяя предыдущее значение каждым новым.
async function *countDown(count: number) {
while (count > 0) {
yield count--;
await new Promise((r) => setTimeout(r, 1000));
}
}
@customElement('my-element')
class MyElement extends LitElement {
@state()
private timer = countDown(10);
render() {
return html`Timer: <span>${asyncReplace(this.timer)}</span>.`;
}
}
async function *countDown(count) {
while (count > 0) {
yield count--;
await new Promise((r) => setTimeout(r, 1000));
}
}
class MyElement extends LitElement {
static properties = {
timer: {state: true},
};
constructor() {
super();
this.timer = countDown(10);
}
render() {
return html`Timer: <span>${asyncReplace(this.timer)}</span>.`;
}
}
customElements.define('my-element', MyElement);Подробнее изучите asyncReplace в песочнице.
© Google LLC
Licensed under the Creative Commons Attribution 3.0 Unported License.
https://lit.dev/docs/v2/templates/directives/