SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

再利用性とカプセル化のためのWeb Componentsを基礎から学ぶ

Web Componentsを簡単に便利に扱うライブラリ「Lit」とは?【うまく活用する方法を紹介】

再利用性とカプセル化のためのWeb Componentsを基礎から学ぶ 第3回

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめてのLit

 それでは、Litを使って、初めてのカスタム要素を作ってみましょう。公式ドキュメントにはNPMを使ってインストールする方法も解説されていますが、せっかくなので、ブラウザの import 機能(JavaScriptモジュール)を使って、Litを利用してみます。

 まずは、HTMLファイルを用意します(リスト2)。

[リスト2]index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <!-- (1) -->
  <script type="module" src="./index.js"></script>
  <title>はじめてのLit</title>
</head>
<body>
  <!-- (2) -->
  <my-element></my-element>
</body>
</html>

 (1)では古き良き <script> タグとは違った形でJavaScriptの読み込みを行っています。今回はNPMを使わずにJavaScriptモジュールを使用するので、 type="module" 属性を指定して、読み込んだ index.js のファイル内でJavaScriptモジュールの文法が利用できるようにしました。

 また、 index.js の内部でカスタム要素を定義する予定なので、先行して(2)で <my-element> というカスタム要素のタグを実装してあります。

 次は、JavaScriptファイルを用意します(リスト3)。

[リスト3]index.js
// (1)
import {LitElement, html} from 'https://cdn.jsdelivr.net/gh/lit/dist@2/core/lit-core.min.js';

class MyElement extends LitElement {
  render() {
    return html`
      <h1>Hello World!</h1>
    `;
  }
}

customElements.define('my-element', MyElement);

 大部分はリスト1で解説した通りですが、このリスト3で実際に動かすにあたって、(1)でモジュールを読み込む方法がリスト1と変わっています。NPMを前提としたプログラムでは、import文のfrom以降にはモジュール名( "lit" など)を記載しますが、JavaScriptモジュール仕様では、モジュールのURLを直接指定します。特別にインストールの作業を行う必要はないのです。

 さて、実は前述の2ファイルだけで、最低限の実装は完了しています。Webサーバーに各ファイルを配置して、 index.html を表示してみます(図4)。

図4:テンプレートが表示された
図4:テンプレートが表示された

 期待した通り、「Hello World!」が表示されましたね。DOMツリーを確認してみると、シャドウホストである <my-element> に紐づけられたシャドウルートの下に、 render() でテンプレートとして実装した <h1>Hello World!</h1> が描画されていることがわかります。

 大きく手間ひまをかけずに、Litでの開発環境構築ができました。

[コラム]別バージョンのLitを利用する

 本文を読んでから少し時間が経つと、リスト3とは別のバージョンの(より新しい)モジュールを利用したくなることが出てくると思います。その場合は、公式ドキュメントに記載の通り、次のページから lit-core.min.js や lit-all.min.js を探して、import文に記載してください。

 lit-core.min.js には、Litでカスタム要素を成立させるための、最低限の機能( html や LitElement )のみが含まれています。一方、 lit-all.min.js には、coreの内容に加えて、テンプレート内で複雑な操作を行う際に使える便利関数(ディレクティブと呼ばれています)などが含まれます。

 本記事では最低限の機能を解説しているため、 lit-core.min.js を使っていますが、次回は少し込み入った内容にも挑戦するため、 lit-all.min.js を使用する予定です。

プロパティを管理する

 単純なテキストの表示ができたので、次は動的なデータを表示する方法について学んでいきましょう。LitElement で作成したカスタム要素のクラスには、表示内容を切り替えるための「プロパティ(properties)」と呼ばれるデータを定義できます。リスト4に簡単な例を挙げます。

[リスト4]properties.js
import {LitElement, html} from 'https://cdn.jsdelivr.net/gh/lit/dist@2/core/lit-core.min.js';

class MyElement extends LitElement {
  static properties = {
    name: {}, // (1)
  }

  constructor() {
    super();
    this.name = "名無し"; // (2)
  }

  render() {
    return html`
      <h1>プロパティのサンプル</h1>
      <p>こんにちは、${this.name}さん!</p><!-- (3) -->
    `;
  }
}

customElements.define('my-element', MyElement);

 まずは、staticプロパティの properties の中で、(1)のように扱いたいプロパティの名前とオプションを設定します。今回は name という名前にしたので、このクラス内では this.name が更新可能なプロパティとして LitElement に認識されます。特にオプションは必要なかったので、空オブジェクト( {} )にしました。

 次は(2)のコンストラクタ内で値の初期化を行います。適切な初期値を指定します。そして、(3)でテンプレート内にプロパティを埋め込みました。通常のテンプレートリテラルに値を埋め込む場合と同様に ${} で変数名を囲んでいます。

 次は、リスト4をリスト5のHTMLで表示してみましょう。

[リスト5]properties.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="module" src="./properties.js"></script>
  <title>Litのプロパティ</title>
</head>
<body>
  <!-- (1) -->
  <my-element></my-element>
</body>
</html>

 内容としてはリスト2とほとんど同じで、ファイル名が変わった程度です。強いていえば、(1)で何も属性をつけていない点には注目しておいてください。

 リスト5を表示すると、図5のような表示になります。

図5:プロパティを利用した表示
図5:プロパティを利用した表示

 ちゃんと値が埋め込まれていますね。 実は、 properties に指定したプロパティは、カスタム要素の属性としても利用できます。 <my-element> に name 属性を付与してみたのがリスト6です。

[リスト6]properties.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="module" src="./properties.js"></script>
  <title>Litのプロパティ</title>
</head>
<body>
  <!-- (1) -->
  <my-element name="田中"></my-element>
</body>
</html>

 (1)でカスタム要素に name="田中" という属性をつけました。これを表示すると、図6のようになります。

図6:プロパティを外部から属性で指定する
図6:プロパティを外部から属性で指定する

 テンプレートの ${this.name} の部分が「田中」で表示されました。このように、プロパティを定義すると外部からもパラメータとして指定できるようになります。

プロパティのオプション

 properties にプロパティを定義する際に、リスト7のような形でオプションを付与することができます。

[リスト7]プロパティのオプションを定義する
static properties = {
  count: {
    attribute: false,
    type: Number,
  },
}

 指定できるオプションは表1の通りです。

表1:プロパティに指定できるオプション
オプション名 概要
attribute プロパティをHTMLタグの属性として利用できるかどうか
converter 属性から複雑な値を渡された場合にクラス内の値と相互変換するための関数
hasChanged プロパティに更新があった場合に呼び出されるコールバック
noAccessor Litがスーパークラスのアクセサを上書きしないようにする
reflect プロパティの更新に応じて、DOMツリーの属性情報を書き換える
state クラス内でのみ利用し、属性としては利用しない
type 属性で受け取った文字列型をクラス内で何型に変換するか

 これらのオプションを組み合わせることで、HTMLタグとして記述した場合に属性から受け取ったデータをどのように扱うかを調整できます。これらのオプションについては、次回、他の機能の状態管理に使いながら解説します。

イベントを扱う

 LitElement で作ったカスタム要素がプロパティを持てることは分かりましたが、ある程度動きのあるUIを作ろうとすると、クリックイベントを扱ったり、イベントに応じてプロパティを更新したりしたくなりますよね。

 続いては、イベントを扱う方法について解説します。簡単な例として、ボタンを押すと数字のカウントが0から一つずつ増えていくアプリケーションを用意しました(リスト8)。

[リスト8]event.js
import {LitElement, html} from 'https://cdn.jsdelivr.net/gh/lit/dist@2/core/lit-core.min.js';

class MyElement extends LitElement {
  static properties = {
    count: { type: Number, reflect: true }
  }

  constructor() {
    super();
    this.count = 0;
  }

  render() {
    return html`
      <h1>イベントのサンプル</h1>
      <p>カウント: ${this.count}</p>
      <!-- (1) -->
      <button @click="${() => this._increment()}">+1</button>
    `;
  }

  // (2)
  _increment() {
    this.count += 1;
  }
}

customElements.define('my-element', MyElement);

 (1)にボタンを定義しました。HTMLのクリックイベントでは click 属性を使いますが、今回は @click という見慣れない属性を使っています。これは、Litがイベントハンドリングを行うための特殊な属性です。 @click の値として関数を指定することで、クリック時に関数が呼び出されます。今回は(2)に定義した _increment() がクリックのたびに実行されます。 this.count は properties に定義済みなので、データを更新するとUIも更新されます。

 リスト7を実際に動かしてみた様子が図7です。

図7:ボタンを押すとカウントが上がる
図7:ボタンを押すとカウントが上がる

 このように、Litではインタラクションを伴う処理も比較的簡単に記述できます。

まとめ

 今回はLitの動作環境の構築と、簡単な使い方について学びました。次回は、もう少し込み入った属性の使い方や、リスト表示の方法について学んでいきます。お楽しみに。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
再利用性とカプセル化のためのWeb Componentsを基礎から学ぶ連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 中川幸哉(ナカガワユキヤ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/16814 2022/11/24 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング