SHOEISHA iD

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

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

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

Web Componentsを簡便に扱う「Lit」の実践的な使い方を学ぶ──ToDoリストを作ろう

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

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

チェック状態の変更をハンドリングしてスタイルを変更する

 さて、現在の実装では、チェックボックスをクリックしたときにチェック状態が切り替わったように見えても、 tasks プロパティの内容は変わっていません。DOMツリーの状態が独自に変わっているだけです。ですが、打ち消し線を制御する過程で、 tasks の内容も変更されていたほうが都合が良いので、変更する仕組みを実装していきましょう。チェックボックスのクリックイベントを受けて、状態の更新を行うので、まずはクリックイベントを受け取る処理を記述します(リスト5)。

[リスト5]チェックボックスのクリックイベントを受け取る
<input
  type="checkbox"
  ?checked=${task.completed}
  @click=${(event) => this.setChecked(task, event)}
/>

 イベントリスナーを登録するので、 @ のプレフィックスをつけた @click に関数を登録します。ここで呼び出す関数は、クラス内のメソッドとして定義します(リスト6)。

[リスト6]状態を更新する
setChecked(task, event) {
  task.completed = event.target.checked; // (1)
  this.requestUpdate(); // (2)
}

 ここでは、(1)でデータを更新し、(2)でDOMへの再描画を依頼しています。 this.tasks を直接書き換えれば自動で再描画されるのですが、今回は配列の要素を書き換えているので、(2)のように明示的に再描画のメソッドを呼び出しています。

 これでデータとUIが同期するようになったので、次は完了状態のタスクに打ち消し線を表示できるようにしましょう。Litでカスタム要素内のスタイルを表現する場合は、styles という名前のstaticプロパティを定義します(リスト7)。

[リスト7]スタイルを定義する
// (1) cssを追加する
import {LitElement, html, map, css} from 'https://cdn.jsdelivr.net/gh/lit/dist@2/all/lit-all.min.js';
// 略
// (2) スタイルを定義する
static styles = css`
  .completed {
    text-decoration-line: line-through;
    color: #777;
  }
`;
// 略

 スタイルの定義には、 css というタグ付きのテンプレートリテラルを利用します。 css は(1)のようにインポートして使用します。テンプレートリテラル内には(2)のようにCSSを記述できます。

 スタイルを定義したので、テンプレート側にも対応するclass属性を定義します(リスト8)。

[リスト8]テンプレートにclass属性を定義する
<li class=${task.completed ? 'completed' : ''}>

 <li> 要素にclass属性を追加しました。 task.completed がtrueの場合だけ、 class="completed" が設定されることになります。リスト7で .completed のセレクタに対して打ち消し線と色変更を設定してあるので、実行すると図4のようになります。

図4:打ち消し線が表示された
図4:打ち消し線が表示された

 動的なデータ変更に応じて、スタイルを変更できるようになりました。

完了したタスクを隠す

 最後に、プロパティをもう一つ追加して、完了した項目を隠せるようにしてみましょう。リスト9のようにプロパティを追加します。

[リスト9]タスクを隠すためのプロパティを追加
static properties = {
  tasks: {
    state: true,
  },
  // (1) 追加
  hideCompleted: {
    type: Boolean,
    reflect: true, // (2)
  },
};

 tasks の定義の下に、(1)のように hideCompleted というプロパティを追加しました。(2)で reflect: true を設定したのは、後でスタイルの切り替えに使用するためです。

 では、次は hideCompleted のオンオフを切り替えるためのチェックボックスを追加しましょう(リスト10)。

[リスト10]タスクを隠すためのチェックボックスを追加
// 略
<h1>ToDoリスト</h1>
${map(this.tasks, (task) => {
  // 略
})}
<hr />
<div>
  <!-- (1) -->
  <label>
    <input type="checkbox"
      @change=${this.setHideCompleted /* (2) */ }
      ?checked=${this.hideCompleted}>
    完了したタスクを隠す
  </label>
</div>
// 略

 (1)にチェックボックスを追加しました。表示すると図5のようになります。

図5:完了したタスクを隠すUIを追加
図5:完了したタスクを隠すUIを追加

 まだ(2)で @change にイベントリスナーとして登録している setHideCompleted メソッドを実装していないので、実装します(リスト11)。

[リスト11]項目を隠すメソッドを実装する
setHideCompleted(event) {
  this.hideCompleted = event.target.checked;
}

 今回はリスト6とは違い、 requestUpdate() は使用しません。 hideCompleted には reflect: true を設定してあるので、データを更新した時点で変更が反映されます。

 次はスタイルの追加……といきたいところですが、まずは reflect: true の効果について確認しておきましょう。 reflect: true はカスタム要素内部でのプロパティの更新を、属性の変更としてDOMに反映するためのオプションです(図6)。

図6:プロパティの変更がDOMの属性に反映される
図6:プロパティの変更がDOMの属性に反映される

 カスタム要素の内部で hideCompleted がtrueになっているとき、DOM上では <todo-list hidecompleted> のように、 hidecompleted 属性が設定されるのです。これは hideCompleted が更新されるたびに反映されます。

 この仕組みは、スタイル定義と組み合わせた場合に上手く機能します。スタイルの定義に、リスト12のような新しいスタイルを追加します。

[リスト12]スタイルを追加
static styles = css`
  .completed {/* 略 */}
  /* (1) 追加 */
  :host([hideCompleted]) li.completed {
    display: none;
  }
`;

 (1)での :host() はCSSの擬似クラス関数で、引数にセレクタを渡すことで、シャドウホスト(ここでは <todo-list>)の属性を見ながらスタイルを指定できます。そのため、(1)が意味するところは「シャドウホストに hideCompleted 属性が指定されている場合、class属性に completed が指定された <li> 要素を表示しない」というものになります。実際に動かしてみると、図7のようになります。

図7:チェックを付けると項目が隠れる
図7:チェックを付けると項目が隠れる

 しっかりとスタイルが効いていますね。 reflect を設定したプロパティをCSSセレクタに利用する使い方は便利なので、ぜひご活用ください。

まとめ

 今回は、ToDoリストを作りながらLitで状態管理を行う方法について学びました。次回は外部のUIライブラリを利用してリッチなUIを作成する方法について解説します。

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

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

もっと読む

この記事の著者

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

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

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング