JavaScript | 1 日 60 分 × 7 日アプリ学習:JavaScript基礎・DOM操作 おみくじ編

Web APP JavaScript
スポンサーリンク
スポンサーリンク

4日目のゴールと全体像

おみくじアプリ 4日目のテーマは 「おみくじの結果を“履歴として残し”、一覧表示・削除ができるようにして、DOM操作とイベント処理、ローカルストレージの基礎をまとめて体験すること」 です。

ここまでで、みなさんは

  • ランダムに結果を選ぶ
  • 結果ごとにメッセージ・背景色・ラッキーアイテムを表示する

という「その場で楽しめるおみくじ」を作ってきました。

4日目ではここに “履歴機能” を加えて、

  • 結果を配列として保存する
  • ローカルストレージに履歴を保存・読み込みする
  • 履歴をカード風に一覧表示する
  • 履歴を削除するボタンをつける

という、Webアプリらしい「データ管理」の要素を取り入れていきます。

履歴機能のイメージと設計

まず、どんな履歴を残したいかを決めます。

  • 引いた日時
  • 結果(大吉・中吉など)
  • ランク(数値)
  • ラッキーアイテム

これらを 1回のおみくじにつき1つのオブジェクト として保存し、 それを配列にどんどん追加していくイメージです。

履歴1件分のデータ構造(オブジェクト)

const historyItem = {
  dateTime: "2026-08-06 14:30",
  result: "大吉",
  rank: 5,
  luckyItem: "赤いペン"
};
JavaScript

履歴全体(配列)

const historyArray = [
  { dateTime: "...", result: "...", rank: ..., luckyItem: "..." },
  { dateTime: "...", result: "...", rank: ..., luckyItem: "..." },
  // ...
];
JavaScript

この「配列+オブジェクト」の組み合わせは、 Webアプリでデータを扱うときの超基本パターン です。

HTMLに履歴表示エリアを追加する

まずは、履歴を表示する場所を用意します。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>おみくじアプリ 4日目</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h2>おみくじ</h2>

  <button id="omikujiBtn">おみくじを引く</button>

  <p id="result"></p>
  <p id="message"></p>
  <p id="luckyItem"></p>

  <h3>履歴</h3>
  <!-- 履歴一覧を表示するエリア -->
  <div id="historyList"></div>

  <!-- 履歴をすべて削除するボタン -->
  <button id="clearHistoryBtn">履歴をすべて削除</button>

  <script src="script.js"></script>
</body>
</html>

押さえておきたいポイント

  • id="historyList"<div> に、JavaScriptから履歴カードを追加していきます。
  • id="clearHistoryBtn" のボタンで、履歴全削除機能を作ります。

CSSで履歴カードの見た目を整える

履歴を「カード風」にすると、見やすくなります。

body {
  font-family: sans-serif;
  padding: 20px;
  transition: background-color 0.5s;
}

#result {
  font-size: 24px;
  margin-top: 20px;
}

#message {
  font-size: 16px;
  margin-top: 10px;
}

#luckyItem {
  font-size: 18px;
  margin-top: 15px;
  font-weight: bold;
}

/* 履歴カードのスタイル */
.history-card {
  background: #fff;
  padding: 10px;
  margin: 8px 0;
  border-radius: 6px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.history-card p {
  margin: 4px 0;
}

.history-delete-btn {
  margin-top: 6px;
  padding: 4px 8px;
  cursor: pointer;
  font-size: 12px;
}

深掘りポイント

  • .history-card は「履歴1件分の見た目」を定義するクラス。
  • JavaScriptからこのクラスを付けた <div> を作ることで、 「データ → 画面」への橋渡し ができる。

ローカルストレージで履歴を保存・読み込みする

ローカルストレージとは

ブラウザにデータを保存しておける仕組みです。 ページを閉じても、再読み込みしても、データが残ります。

  • 保存:localStorage.setItem("キー", "文字列")
  • 読み込み:localStorage.getItem("キー")

配列やオブジェクトはそのままでは保存できないので、 JSON文字列に変換して保存 します。

履歴配列の宣言と読み込み

// 履歴を入れておく配列
let historyArray = loadHistory();

// 履歴を読み込む関数
function loadHistory() {
  const data = localStorage.getItem("omikujiHistory");
  // 保存されていなければ空配列を返す
  return data ? JSON.parse(data) : [];
}
JavaScript

履歴を保存する関数

function saveHistory(arr) {
  // 配列をJSON文字列に変換して保存
  localStorage.setItem("omikujiHistory", JSON.stringify(arr));
}
JavaScript

深掘りポイント

  • JSON.stringify(arr) で配列を文字列に変換。
  • JSON.parse(data) で文字列を配列に戻す。
  • 「保存するときは文字列にする」「読み込むときは元に戻す」という流れを覚える。

履歴を追加する処理を作る

おみくじボタンが押されたときに、 「今回の結果」を履歴配列に追加します。

omikujiBtn.addEventListener("click", function() {
  const randomResult = getRandomResult();
  const data = omikujiData[randomResult];

  result.textContent = `今日の運勢は「${randomResult}」です`;
  message.textContent = data.message;
  updateBackgroundByRank(data.rank);

  const item = getRandomItem();
  luckyItem.textContent = `今日のラッキーアイテム:${item}`;

  // 現在日時を文字列で作る
  const now = new Date();
  const dateTimeText = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()} ${now.getHours()}:${now.getMinutes()}`;

  // 履歴1件分のオブジェクトを作る
  const historyItem = {
    dateTime: dateTimeText,
    result: randomResult,
    rank: data.rank,
    luckyItem: item
  };

  // 配列に追加
  historyArray.push(historyItem);

  // ローカルストレージに保存
  saveHistory(historyArray);

  // 画面に履歴を再描画
  renderHistory(historyArray);
});
JavaScript

深掘りポイント

  • 「今の結果」をオブジェクトにまとめてから配列に追加している。
  • データを追加したら、必ず saveHistory()renderHistory() を呼ぶ。
  • 「データを変える → 保存する → 画面を更新する」という流れが大事。

履歴を画面に表示する(DOM操作)

履歴配列をもとに、カードを生成して表示します。

function renderHistory(historyArray) {
  const list = document.getElementById("historyList");

  // いったん中身を空にする
  list.innerHTML = "";

  // 配列の中身を1件ずつカードにして追加
  historyArray.forEach((item, index) => {
    // カード用のdivを作る
    const card = document.createElement("div");
    card.className = "history-card";

    // カードの中身(HTML)を作る
    card.innerHTML = `
      <p>日時:${item.dateTime}</p>
      <p>結果:${item.result}(ランク:${item.rank})</p>
      <p>ラッキーアイテム:${item.luckyItem}</p>
      <button class="history-delete-btn">この履歴を削除</button>
    `;

    // 削除ボタンのイベントを登録
    const deleteBtn = card.querySelector(".history-delete-btn");
    deleteBtn.addEventListener("click", function() {
      deleteHistory(index);
    });

    // カードを履歴リストに追加
    list.appendChild(card);
  });
}
JavaScript

深掘りポイント

  • .innerHTML = "" で一度全消し → そのあと配列の内容を全部描画し直す。
  • .forEach() で配列の各要素に対して処理を行う。
  • createElement() で新しい要素を作り、appendChild() で追加する。
  • カードごとに削除ボタンをつけて、index を使ってどの履歴かを特定している。

履歴を削除する処理

個別削除

function deleteHistory(index) {
  // index番目の要素を1つ削除
  historyArray.splice(index, 1);

  // 保存し直す
  saveHistory(historyArray);

  // 画面を更新
  renderHistory(historyArray);
}
JavaScript

全削除ボタンの処理

const clearHistoryBtn = document.getElementById("clearHistoryBtn");

clearHistoryBtn.addEventListener("click", function() {
  // ローカルストレージから削除
  localStorage.removeItem("omikujiHistory");

  // 配列を空にする
  historyArray = [];

  // 画面を更新
  renderHistory(historyArray);
});
JavaScript

深掘りポイント

  • splice(index, 1) は「配列のindex番目から1つ削除する」メソッド。
  • 全削除では removeItem("omikujiHistory") でローカルストレージから消す。
  • データを変えたら必ず renderHistory() を呼んで画面を更新する。

4日目の完成コード(script.js 全体)

const omikujiBtn = document.getElementById("omikujiBtn");
const result = document.getElementById("result");
const message = document.getElementById("message");
const luckyItem = document.getElementById("luckyItem");
const clearHistoryBtn = document.getElementById("clearHistoryBtn");

// 結果候補
const results = ["大吉", "中吉", "小吉", "吉", "末吉", "凶"];

// 結果データ
const omikujiData = {
  "大吉": { rank: 5, message: "最高の一日になりそうです。思い切って新しいことに挑戦してみましょう!" },
  "中吉": { rank: 4, message: "良い流れが来ています。コツコツ続けていることが実を結びそうです。" },
  "小吉": { rank: 3, message: "少しずつ前に進める日。焦らず、目の前のことを丁寧にこなしましょう。" },
  "吉":   { rank: 2, message: "穏やかな一日。周りの人との会話を大切にすると、良いヒントが得られます。" },
  "末吉": { rank: 1, message: "まだ結果は見えないけれど、準備をしておくと後で役に立ちます。" },
  "凶":   { rank: 0, message: "無理をせず休むことも大事。今日は慎重に行動してみましょう。" }
};

// ラッキーアイテム
const luckyItems = [
  "赤いペン", "お気に入りの本", "コーヒー", "新しいノート",
  "青い服", "散歩", "音楽プレイリスト", "ストレッチ", "おいしいお菓子"
];

// 履歴配列(ローカルストレージから読み込み)
let historyArray = loadHistory();

// ランダムに結果を選ぶ
function getRandomResult() {
  const index = Math.floor(Math.random() * results.length);
  return results[index];
}

// ラッキーアイテムを選ぶ
function getRandomItem() {
  const index = Math.floor(Math.random() * luckyItems.length);
  return luckyItems[index];
}

// 背景色変更
function updateBackgroundByRank(rank) {
  if (rank === 5) document.body.style.backgroundColor = "#fff8b3";
  else if (rank === 4) document.body.style.backgroundColor = "#cce5ff";
  else if (rank === 3) document.body.style.backgroundColor = "#d4edda";
  else if (rank === 2) document.body.style.backgroundColor = "#e2d4ff";
  else if (rank === 1) document.body.style.backgroundColor = "#ffe5b4";
  else document.body.style.backgroundColor = "#f8d7da";
}

// 履歴を保存
function saveHistory(arr) {
  localStorage.setItem("omikujiHistory", JSON.stringify(arr));
}

// 履歴を読み込み
function loadHistory() {
  const data = localStorage.getItem("omikujiHistory");
  return data ? JSON.parse(data) : [];
}

// 履歴を描画
function renderHistory(historyArray) {
  const list = document.getElementById("historyList");
  list.innerHTML = "";

  historyArray.forEach((item, index) => {
    const card = document.createElement("div");
    card.className = "history-card";

    card.innerHTML = `
      <p>日時:${item.dateTime}</p>
      <p>結果:${item.result}(ランク:${item.rank})</p>
      <p>ラッキーアイテム:${item.luckyItem}</p>
      <button class="history-delete-btn">この履歴を削除</button>
    `;

    const deleteBtn = card.querySelector(".history-delete-btn");
    deleteBtn.addEventListener("click", function() {
      deleteHistory(index);
    });

    list.appendChild(card);
  });
}

// 履歴を1件削除
function deleteHistory(index) {
  historyArray.splice(index, 1);
  saveHistory(historyArray);
  renderHistory(historyArray);
}

// おみくじボタン
omikujiBtn.addEventListener("click", function() {
  const randomResult = getRandomResult();
  const data = omikujiData[randomResult];

  result.textContent = `今日の運勢は「${randomResult}」です`;
  message.textContent = data.message;

  updateBackgroundByRank(data.rank);

  const item = getRandomItem();
  luckyItem.textContent = `今日のラッキーアイテム:${item}`;

  const now = new Date();
  const dateTimeText = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()} ${now.getHours()}:${now.getMinutes()}`;

  const historyItem = {
    dateTime: dateTimeText,
    result: randomResult,
    rank: data.rank,
    luckyItem: item
  };

  historyArray.push(historyItem);
  saveHistory(historyArray);
  renderHistory(historyArray);
});

// 全履歴削除ボタン
clearHistoryBtn.addEventListener("click", function() {
  localStorage.removeItem("omikujiHistory");
  historyArray = [];
  renderHistory(historyArray);
});

// ページ読み込み時に履歴を表示
renderHistory(historyArray);
JavaScript

4日目で本当に掴んでほしいこと

● 「データ → 保存 → 画面」の流れがアプリの基本

  • データをオブジェクト・配列で管理する
  • ローカルストレージに保存する
  • DOM操作で画面に反映する

この流れが理解できると、 メモアプリ・TODOアプリ・日記アプリなど、 いろいろなWebアプリに応用できます。

● DOM操作は「画面を再構築する力」

  • innerHTML = "" で一度消す
  • forEach で配列からカードを作る
  • appendChild で追加する

これが「一覧表示」の基本パターンです。

次の5日目では、 この履歴機能をさらに育てて 並び替え・詳細表示・UI改善 に進んでいきます。

タイトルとURLをコピーしました