12.4 クラスによるデータ管理とUI反映
取得したデータを整理するための 「クラス」 と、画面を書き換えるための 「DOM 操作」 を追加します。
book-search.js の末尾に以下のソースを追加します
ソースフォルダ:public/ch12
ファイル名:book-search.js
// 書籍データを効率的に管理するためのクラス
class BookManager {
constructor() {
this.books = []; // データを保持するプロパティ
}
// 取得したデータをクラス内にセットします
setBooks(data) {
this.books = data;
}
// 画面表示に不要な情報を削り、整形されたデータを返します
getProcessedItems() {
// mapを使って、idとtitleだけの新しいオブジェクト配列を作成します
return this.books.map(book => ({
id: book.id,
title: book.title
}));
}
}
// 画面のリスト(ul要素)を更新する関数
function renderList(items) {
const listElement = document.querySelector("#book-list");
listElement.innerHTML = ""; // 一度中身を空にして初期化します
// 1件ずつHTML要素(liタグ)を作成して追加します
items.forEach(item => {
const li = document.createElement("li"); // <li>を作成
li.textContent = `[ID:${item.id}] ${item.title}`; // テキストを設定
listElement.appendChild(li); // ulの中に追加
});
}
解説
23 行目から始まる renderList 関数は、取得したデータを実際に画面に表示する役割を持ちます。
関数の責務と分離の意図
なぜこの関数を独立させているのでしょうか?
【設計の原則:責務の分離】
- BookManager クラス: データの管理・加工
- renderList 関数: 画面への表示
- setupSearch 関数: 検索機能(後述)
それぞれが明確な役割を持つことで、「どこを修正すればいいか」が一目瞭然になります。例えば、表示デザインを変更したい場合は、renderList 関数だけを修正すればよく、データ管理のコードには手を付ける必要がありません。
DOM 操作の流れ(ステップバイステップ)
24 行目から 32 行目の処理を順番に見ていきましょう
【ステップ 1】要素の取得
HTML の <ul id=”book-list”></ul>要素を JavaScript から操作できるオブジェクトとして取得します。
第 8 章で学んだ querySelector ですね。
24: const listElement = document.querySelector("#book-list");
【ステップ 2】既存内容のクリア
リストの中身を空にします。これを行わないと、renderList を呼ぶたびに古いデータが残ったまま新しいデータが追加されてしまいます。
25: listElement.innerHTML = "";
【動作イメージ】
初回表示: [データ A, データ B, データ C]
クリアなし: [データ A, データ B, データ C, データ A, データ B, データ C]
クリアあり: [データ A, データ B, データ C] ← 毎回リセットされる
【ステップ 3-6】forEach でのループ処理
引数 items の配列要素 1 つ 1 つに対して処理を実行します。
28: items.forEach(item => {
29: const li = document.createElement("li");
30: li.textContent = `[ID:${item.id}] ${item.title}`;
31: listElement.appendChild(li);
32: });
各ループで行うこと:
- 新しい<li>要素を作成(29行目)
- その<li>の中身を設定(30行目)
- <ul>の中に追加(31行目)
textContent と innerHTML の違い
61 行目で textContent を使っていますが、innerHTML との違いは何でょうか。
【textContent(推奨)】
- テキストとして扱う
- HTML タグは無効化される
- XSS 攻撃を防げる(セキュリティ上安全)
【innerHTML】
- HTML として解釈されるため、タグも有効になる
- ユーザーが入力したデータを含む場合は危険
【具体例】
悪意のあるデータ: “<script>alert(‘攻撃’)</script>”
textContent の場合:
→ “<script>alert(‘攻撃’)</script>” とそのまま表示される(安全)
innerHTML の場合:
→ スクリプトが実行されてしまう(危険)
今回は単純なテキスト表示なので textContent を使っています。
