ビルトインディレクティブ

ディレクティブを使うとエクスプレッションのレンダリング方法を変更することによってLitを拡張することができます。 Litは下記のような多様な用途に対応したビルドインディレクティブを用意しています。

ディレクティブサマリー

スタイル

classMap

渡されたobjectに応じて要素にclass属性を割り当てます。

styleMap

渡されたobjectに応じて要素にstyle属性を割り当てます。

繰り返しと条件

when

条件に応じて渡された2つのテンプレートの内1つをレンダリングします。

choose

オブジェクトのキーの値に応じて指定した多数のテンプレートの内1つをレンダリングします。

map

iterableの各値を指定した関数で変換します。

repeat

iterableの各値をDOMにレンダリングします。オプションでそれらにkeyを付与する処理を追加することができます。

join

iterableの各値を指定した値で連結します。

range

連続した数値を値に持つiterableを生成します。これは繰り返しの回数を指定する際に便利です。

ifDefined

値が定義されている場合は属性をセットします。undefinedの場合は属性を削除します。

キャッシュと変更の検出

cache

テンプレートを変更した時、DOMを破棄するのではなくレンダリング済みのDOMをキャッシュします。

keyed

レンダリング可能な値とユニークなキーを関連付けます。そして、キーが変化すると強制的に関連付けられた値が強制的に再レンダリングされます。

guard

指定した変更を検知するための値の内1つが変更された場合のみテンプレートを再評価します。

live

最後にレンダリングされた時の値が現行のDOMの属性もしくはプロパティと異なっていた場合、それに値をセットします。

レンダリングされたDOMの参照

ref

テンプレートでレンダリングされた要素の参照を取得します。

特殊な値のレンダリング

templateContent

<template>要素のコンテンツをレンダリングします。

unsafeHTML

文字列をテキストではなくHTMLとしてレンダリングします。

unsafeSVG

文字列をテキストではなくSVGとしてレンダリングします。

非同期レンダリング

until

1つ以上のPromiseが解決するまでプレイスフォルダのコンテンツをレンダリングします。

asyncAppend

AsyncIterableの各値を解決される毎にDOMに追記していきます。

asyncReplace

AsyncIterableの各値を解決される毎にDOMを置き換えます。

独自のディレクティブを作成することができます。 詳しくはカスタムディレクティブを見てください。

スタイル

classMap

渡されたobjectに応じて要素のclass属性にclass名のリストを割り当てます。

Import
import {classMap} from 'lit/directives/class-map.js';
API
classMap(classInfo: {[name: string]: string | boolean | number})
使用可能な場所

class属性に対応するエクスプレッション

classMapディレクティブは渡されたオブジェクトに応じてelement.classListを使って効率的にclass属性に値を追加および削除します。 オブジェクトの各キーはclass名です。その値がtrueと評価できる場合、要素のclass属性にそのclass名を加えます。 その後のレンダリングでは、1つ前のレンダリングでclass属性にセットされていたclass名のうち値がfalseと評価できるものやオブジェクトにキーが存在しないものはclass属性から削除されます。

@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>`;
  }
}

classMapは下記のようにclass属性の静的な値と組み合わせることができます。

html`<div class="my-widget ${classMap(dynamicClasses)}">Static and dynamic</div>`;

classMapを使用した例はこちらです。

styleMap

渡されたobjectに応じて要素にstyleプロパティのリストを割り当てます。

Import
import {styleMap} from 'lit/directives/style-map.js';
API
styleMap(styleInfo: {[name: string]: string | undefined | null})
使用可能な場所

style属性に対応するエクスプレッション

styleMapディレクティブは渡されたオブジェクトに応じてelement.style APIを使って効率的に要素のstyle属性にスタイルを追加したり削除したりします。 渡されたオブジェクトの各キーはスタイルのプロパティ名になります。その値はスタイルのプロパティの値になります。 その後のレンダリングでは、値がセットされていなかったりnullの場合は1つ前のレンダリングでセットされていたスタイルプロパティは削除されます。

@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>`;
  }
}

下記のようにCSSプロパティ名に-が含まれている場合、camel-caseにするか、プロパティ名を'内に置きます。 例えば、font-familyfontFamilyもしくは'font-family'にすることができます。

{ fontFamily: 'roboto' }
{ 'font-family': 'roboto' }

CSSカスタムプロパティを参照する場合、下記のようにプロパティ名全体を'内に置きます。

{ '--custom-color': 'steelblue' }

styleMapはstyle属性内の唯一のエクスプレッションでなければなりませんが、下記のように静的な値と組み合わせることができます。

html`<p style="color: white; ${styleMap(moreStyles)}">More styles!</p>`;

詳しくはplaygroundを見てください。

繰り返しと条件

when

条件に応じて渡された2つのテンプレートの内1つをレンダリングします。

Import
import {when} from 'lit/directives/when.js';
API
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にマッチする関数を実行してテンプレートを返します。 caseにはキーとテンプレートを返す関数の配列を渡します。

Import
import {choose} from 'lit/directives/choose.js';
API
choose<T, V>(
  value: T,
  cases: Array<[T, () => V]>,
  defaultCase?: () => V
)
使用可能な場所

どこでも

casesの構造は[caseValue, func]です。 valuecaseValue===で比較されます。 最初にマッチしたものを採用します。 caseValueには任意の型の値を指定することができます。

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

itemsの各値に対してf(value)を実行した結果を格納しているiterableを返します。

Import
import {map} from 'lit/directives/map.js';
API
map<T>(
  items: Iterable<T> | undefined,
  f: (value: T, index: number) => unknown
)
使用可能な場所

どこでも

map()for/of loopの簡単なラッパです。 これはエクスプレッション内でのiterableに対する処理を少しだけ簡単にします。 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

iterableの値をDOMにレンダリングします。その際にDOMの安定性を付与するためにキーをDOMに付与します。

Import
import {repeat} from 'lit/directives/repeat.js';
API
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;
使用可能な場所

Child expression

repeatはiterableからレンダリング対象の値(通常はTemplateResultsの配列)を生成します。 そして、iterableが変更された時、それらを効率的に更新します。 keyFnが渡された場合、キーがDOMに付与されます。 キーとDOMの関係はDOMが移動する更新で維持されます。 これは不要な要素の挿入と削除を最小にすることができるので、一般的にrepeatを使うことは最も効率的な方法です。

keyFnが必要ない場合、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>
    `;
  }
}

keyFnが渡されなかった場合、repeatは単純なmapと似た動きをします。 その場合、DOMは違う値と関連付けられる可能性があります。

詳しくはmapとrepeatの使い分けを見てください。

join

itemsの各値の間にjoinerの値を挿入したiterableを返します。

Import
import {join} from 'lit/directives/join.js';
API
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分だけ増加した一連の整数のiterableを返します。

Import
import {range} from 'lit/directives/range.js';
API
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
import {ifDefined} from 'lit/directives/if-defined.js';
API
ifDefined(value: unknown)
使用可能な場所

Attribute expression

このディレクティブは属性部分に配置された場合、値が定義されていると属性をセットします。値が未定義(undefinedもしくはnull)だと属性を削除します。 他の部分に配置された場合、何もしません。

1つの属性に1つ以上のエクスプレッションが存在する場合、 1つでもifDefinedundefined/null渡されたものがある場合、その属性は削除されます。 これはurlの属性をセットする際に特に便利です。 urlに必要な部分が定義されていない場合、404を防ぐために属性をセットしません。

@customElement('my-element')
class MyElement extends LitElement {

  @property()
  filename: string | undefined = undefined;

  @property()
  size: string | undefined = undefined;

  render() {
    // sizeもしくはfilenameが未定義の場合、src属性はレンダリングさません。
    return html`<img src="/images/${ifDefined(this.size)}/${ifDefined(this.filename)}">`;
  }
}

キャッシュと変更の検出

cache

渡されたテンプレートが変更した時、レンダリングされたDOMを廃棄するのではなくキャッシュします。 大きなテンプレートを頻繁に切り替える場合、このディレクティブを使うことでパフォーマンスが改善されます。

Import
import {cache} from 'lit/directives/cache.js';
API
cache(value: TemplateResult|unknown)
使用可能な場所

Child expression

cacheに渡されたTemplateResultが変更されると、 渡されたテンプレートがレンダリングされたDOMはそれらが使われない時にキャッシュされます。 テンプレートが変更されると、このディレクティブは新しい値に切り替える前に現行のDOM Nodeをキャッシュします。 このディレクティブは過去にレンダリングされた値に戻す時、新しいDOM Nodeを生成するのではなくキャッシュから復元します。

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)
    )}`;
  }
}

Litのデフォルトの動作は、テンプレートを再レンダリングすると、変更された部分のみが更新されます。 必要なDOMのみが作成または削除されます。 しかし、レンダリングされるテンプレートが別のテンプレートに切り替わると、 Litは現行のDOM treeを削除して新しいDOMツリーをレンダリングします。

cacheディレクティブは生成されたDOMをキャッシュします。 上記の例はsummaryViewおよびdetailViewの両方に対するDOMをキャッシュします。 When you switch from one view to another, Lit swaps in the cached version of the new view and updates it with the latest data. This can improve rendering performance when these views are frequently switched.

keyed

ユニークなキーとレンダリング可能な値を関連付けます。 キーが変更されると、 テンプレートの内容が同じでも、 次の値がレンダリングされる前に現行のDOMは削除されて破棄されます。

Import
import {keyed} from 'lit/directives/keyed.js';
API
keyed(key: unknown, value: unknown)
使用可能な場所

すべてのエクスプレッション

keyedはステートを持つ要素をレンダリングしていて重要なデータが変更されて要素のすべてのステートを確実にクリアする必要がある時に役立ちます。 これは基本的にLitのデフォルトのDOMを再利用する方針とは異なります。

keyedは新しい要素にenterやexitのアニメーションを適用にするようなCSSアニメーションを制作する際にも役立ちます。

@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>`;
  }
}

guard

dependenciesが1つでも変更された場合のみテンプレートが再評価されます。 これによってレンダリングの不要な作業を削減することでパフォーマンスが改善されます。

Import
import {guard} from 'lit/directives/guard.js';
API
guard(dependencies: unknown[], valueFn: () => unknown)
使用可能な場所

すべてのエクスプレッション

valueFnの戻り値をレンダリングします。 そしてdependenciesが1つでも===で比較して変更された時だけvalueFnを再評価します。

引数:

guardはデータが変更されるまで高コストの処理を行わないイミュータブルデータパターンに利用することができます。

@customElement('my-element')
class MyElement extends LitElement {

  @property()
  value: string = '';

  render() {
    return html`
      <div>
        ${guard([this.value], () => calculateSHA(this.value))}
      </div>`;
  }
}

上記のケースでは、valueプロパティが変更された時のみ高コストのcalculateSHA関数を実行します。

live

属性やプロパティの値が(最後のレンダリング時の値ではなく)現行のDOMの値と異なる場合、属性やプロパティに値をセットします。

Import
import {live} from 'lit/directives/live.js';
API
live(value: unknown)
使用可能な場所

Attribute expressionもしくはProperty expression

属性やプロパティの値を更新するかの判断は、 Litのデフォルトの動作ではエクスプレッションに最後にセットされた値と比較します。 liveを使うと現行のDOMの属性やプロパティの値と比較します。 詳しくはこちらを見てください。

これはDOMの値がLitの外部から変更される可能性がある場合に役立ちます。 例えば、 <input>要素のvalueプロパティの値をセットするエクスプレッションが配置され、 このvalueプロパティはユーザの入力によって編集可能であり、 custom elementの側でもそのプロパティもしくは属性を変更する場合です。

DOM上の値が変化したがエクスプレッションでセットされた値が変化していない場合、 LitはそのDOM上の値が変化したことを検知することができません。DOM上の値はエクスプレッションでセットされている値で上書きされません。 この挙動を変えたい場合(常にエクスプレッションにセットされた値で上書きしたい場合)はlive()ディレクティブを使います。

@customElement('my-element')
class MyElement extends LitElement {

  @property()
  data = {value: 'test'};

  render() {
    return html`<input .value=${live(this.data.value)}>`;
  }
}

live()は現行のDOMの値と渡された値を===で比較します。そして、それらが等しい場合は何もしません。 つまり、エクスプレッションが型を変換するような場合はlive()を使うべきではありません。 Attribute expressionに対するlive()には文字列のみを渡してください。そうしないとエクスプレッションは常にレンダリング毎に更新を発生させます。

特殊な値のレンダリング

templateContent

<template>要素のコンテンツをレンダリングします。

Import
import {templateContent} from 'lit/directives/template-content.js';
API
templateContent(templateElement: HTMLTemplateElement)
使用可能な場所

Child expression

LitテンプレートはJavaScript内でエンコードされます。 だから、それにJavaScriptのエクスプレッションを埋め込むことでそれを動的にすることができます。 Liテンプレートに静的な<template>要素を組み込みたい場合、templateContentディレクティブを使います。 templateContentディレクティブはテンプレートのコンテンツを複製します。そして、それをLitテンプレートに組み込みます。 template要素の参照が1つ前のレンダリング時と変わらない限り、その後のレンダリングでは何もしません。

template要素のコンテンツは見ず知らずの人が作成した信頼できない文字列が含まれないように注意してください。 信頼できない文字列の例としてクエリパラメータの値やユーザが入力した値があります。 信頼できないtemplate要素のコンテンツをこのディレクティブでレンダリングすることはクロスサイトスクリプティング(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)}`;
  }
}

詳しくはこちらを見てください。

unsafeHTML

文字列をテキストではなくHTMLとしてレンダリングします。

Import
import {unsafeHTML} from 'lit/directives/unsafe-html.js';
API
unsafeHTML(value: string | typeof nothing | typeof noChange)
使用可能な場所

Child expression

Litのテンプレートシンタックスの重要な機能はテンプレートリテラル内の文字列のみがHTMLとしてパースされることです。 テンプレートリテラルは信頼することができるスクリプトファイル内でのみ記述することができるので、 これは信頼することができないHTMLが混入することから生じるXSSに対する根本的な対策です。 しかし、スクリプトファイル以外から得たHTMLをLitテンプレート内でレンダリングする必要がある場合もあるかもしれません。 例えば、データベースからfetchした信頼できる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)}
    `;
  }
}

詳しくはこちらを見てください。

unsafeSVG

文字列をテキストではなくSVGとしてレンダリングします。

Import
import {unsafeSVG} from 'lit/directives/unsafe-svg.js';
API
unsafeSVG(value: string | typeof nothing | typeof noChange)
使用可能な場所

Child expression

unsafeHTMLに似ています。 しかし、スクリプトファイル以外から得たSVGをLitテンプレート内でレンダリングする必要がある場合もあるかもしれません。 例えば、データベースからfetchした信頼できる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> `;
  }
}

詳しくはこちらを見てください。

レンダリングされたDOMの参照

ref

DOMにレンダリングされた1つの要素への参照を取得します。

Import
import {ref} from 'lit/directives/ref.js';
API
ref(refOrCallback: RefOrCallback)
使用可能な場所

Element expression

LitでのほとんどのDOMの操作はテンプレートを使って宣言的に行うことができます。 しかし、テンプレート内のレンダリングされた要素の参照を取得して、それを命令的に操作したい場合があるかもしれません。 これの一般的な例は、フォーム内のコントロールにフォーカスを当てることやコンテナ要素上で命令的なDOM操作をするライブラリを実行することです。

テンプレートの要素上に配置すると、 refディレクティブはレンダリング直後にその要素の参照を取得します。 要素の参照をする方法は2つあります。 それはRefオブジェクトを渡す方法とコールバック関数を渡す方法です。

Refオブジェクトは要素の参照のコンテナの役割を果たします。 RefオブジェクトはrefモジュールのcreateRef関数を使って生成します。 updatedのようなレンダリング後のライフサイクルで、 Refオブジェクトのvalueプロパティに要素がセットされていて使用することができます。

@customElement('my-element')
class MyElement extends LitElement {

  inputRef: Ref<HTMLInputElement> = createRef();

  render() {
    // refディレクティブにRefオブジェクトを渡します。Refオブジェクトのvalueプロパティに要素が格納されます。
    return html`<input ${ref(this.inputRef)}>`;
  }

  firstUpdated() {
    const input = this.inputRef.value!;
    input.focus();
  }
}

コールバック関数をrefディレクティブに渡すことができます。 参照される要素が変更される度、コールバック関数が実行されます。 コールバックが別の要素上でレンダリングされたり、その後のレンダリングで削除された場合、 その後の最初の1回はundefinedが渡されて実行されます。 その後に新しい要素に付与した場合はその要素を渡したコールバック関数が実行されます。 LitElementでは、refディレクティブに渡されたコールバック関数は自動的にhost要素がbindされることに注意してください。

@customElement('my-element')
class MyElement extends LitElement {

  render() {
    // refディレクティブにchangeコールバックを渡します。
    return html`<input ${ref(this.inputChanged)}>`;
  }

  inputChanged(input?: HTMLInputElement) {
    input?.focus();
  }
}

詳しくはこちらを見てください。

非同期レンダリング

until

1つ以上のPromiseが解決するまでプレースホルダのコンテンツをレンダリングします。

Import
import {until} from 'lit/directives/until.js';
API
until(...values: unknown[])
使用可能な場所

すべてのエクスプレッション

untilはPromiseを含む複数の値を引数に取ります。 引数は優先順位が高い値から低い値の順に指定します。 優先順位が高いものに未解決のPtomiseがあった場合、優先順位が低い引数の値でPromiseでない値や解決済みの値がレンダリングされます。

この引数の値の優先順位は非同期でデータを取得する間のプレイスホルダのコンテンツを生成することに利用することができます。 例えば、 解決に時間がかかるPromiseを第1引数(優先順位が1番高い)として渡します。 非Promiseのローディングインディケータテンプレートを第2引数(優先順位が低い)として渡します。 すると、ローディングインディケータはすぐにレンダリングされます。 そして、Promiseが解決されると優先順位が1番高いコンテンツがレンダリングされます。

@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>`)}`;
  }
}

詳しくはこちらを見てください。

asyncAppend

AsyncIterableから値を得る毎にそれをDOMに追記していきます。

Import
import {asyncAppend} from 'lit/directives/async-append.js';
API
asyncAppend(iterable: AsyncIterable)
使用可能な場所

Child expression

asyncAppendasync iterableの各値をレンダリングします。 各値は1つ前の値の後に追記されていきます。 AsyncGeneratorasync iterable protocolsを実装しています。 だから、下記のように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>`;
  }
}

詳しくはこちらを見てください。

asyncReplace

AsyncIterableから得た最新の値をDOMにレンダリングします。値を得る度、1つ前の値のレンダリング結果と置き換えます。

Import
import {asyncReplace} from 'lit/directives/async-replace.js';
API
asyncReplace(iterable: AsyncIterable)
使用可能な場所

Child expression

asyncReplaceasync iterableの各値をレンダリングする点がasyncAppendと似ています。 asyncReplaceAsyncIterableから得た1つ前の値を最新の値に置き換えます。

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>.`;
  }
}

詳しくはこちらを見てください。


License

Japanese part

Creative Commons Attribution-NonCommercial 4.0 International Public License

Copyright (c) 2022 38elements

Other

Creative Commons Attribution 3.0 Unported

Copyright (c) 2020 Google LLC. All rights reserved.

BSD 3-Clause License

Copyright (c) 2020 Google LLC. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.