JavaScript | 1 日 60 分 × 7 日アプリ学習:JavaScript基礎・DOM操作 サイコロ編

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

4日目のゴールと全体像

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

ここまでで、みなさんは

  • 1つのサイコロの結果表示
  • 2つのサイコロの合計値表示
  • 合計値に応じた背景色・メッセージ表示

という「動きのあるサイコロアプリ」を作ってきました。

4日目ではここに 履歴機能 を追加して、

  • サイコロの結果をオブジェクトとして保存
  • 履歴を配列で管理
  • ローカルストレージに保存
  • 履歴をカードUIとして一覧表示
  • 個別削除・全削除

という「データ管理ができるサイコロアプリ」へ進化させます。

履歴機能の設計

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

  • サイコロ1の目
  • サイコロ2の目
  • 合計値
  • 振った日時
  • 合計値に応じたメッセージ

これらを 1件のオブジェクト として保存します。

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

const historyItem = {
  dice1: 4,
  dice2: 6,
  sum: 10,
  dateTime: "2026-08-06 14:20",
  message: "最高の運勢!何をしても楽しめそうです!"
};
JavaScript

履歴全体(配列)

const historyArray = [
  { dice1: 3, dice2: 2, sum: 5, dateTime: "...", message: "..." },
  { dice1: 6, dice2: 6, sum: 12, dateTime: "...", message: "..." }
];
JavaScript

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

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

<h3>履歴</h3>

<div id="historyList"></div>

<button id="clearHistoryBtn">履歴をすべて削除</button>

深掘りポイント

  • id="historyList" に JavaScriptからカードを追加していく
  • id="clearHistoryBtn" で全削除機能を作る
  • DOM操作は「HTML側に置き場所を作る → JSで中身を入れる」が基本

CSSで履歴カードを整える

.history-card {
  background: #fff;
  padding: 12px;
  margin: 10px 0;
  border-radius: 8px;
  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

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

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

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

ローカルストレージとは

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

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

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

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

let historyArray = loadHistory();

function loadHistory() {
  const data = localStorage.getItem("diceHistory");
  return data ? JSON.parse(data) : [];
}
JavaScript

履歴を保存する関数

function saveHistory(arr) {
  localStorage.setItem("diceHistory", JSON.stringify(arr));
}
JavaScript

履歴を追加する処理

サイコロを振ったときに履歴を追加します。

rollBtn.addEventListener("click", function() {
  const n1 = rollDice();
  const n2 = rollDice();
  const sum = n1 + n2;

  dice1.textContent = `サイコロ1:${n1}`;
  dice2.textContent = `サイコロ2:${n2}`;
  diceSum.textContent = `合計:${sum}`;

  updateBackground(sum);
  const msg = getSumMessage(sum);
  diceMessage.textContent = msg;

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

  const historyItem = {
    dice1: n1,
    dice2: n2,
    sum: sum,
    dateTime: dateTimeText,
    message: msg
  };

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

深掘りポイント

  • 「データを作る → 配列に追加 → 保存 → 画面更新」 この流れはどんなアプリでも共通
  • 履歴は「オブジェクト」でまとめると扱いやすい

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

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>サイコロ1:${item.dice1}</p>
      <p>サイコロ2:${item.dice2}</p>
      <p>合計:${item.sum}</p>
      <p>メッセージ:${item.message}</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() が DOM操作の基本

履歴を削除する処理

個別削除

function deleteHistory(index) {
  historyArray.splice(index, 1);
  saveHistory(historyArray);
  renderHistory(historyArray);
}
JavaScript

全削除

clearHistoryBtn.addEventListener("click", function() {
  localStorage.removeItem("diceHistory");
  historyArray = [];
  renderHistory(historyArray);
});
JavaScript

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

const rollBtn = document.getElementById("rollBtn");
const dice1 = document.getElementById("dice1");
const dice2 = document.getElementById("dice2");
const diceSum = document.getElementById("diceSum");
const diceMessage = document.getElementById("diceMessage");
const clearHistoryBtn = document.getElementById("clearHistoryBtn");

let historyArray = loadHistory();

function rollDice() {
  return Math.floor(Math.random() * 6) + 1;
}

function updateBackground(sum) {
  if (sum <= 4) document.body.style.backgroundColor = "#f8d7da";
  else if (sum <= 8) document.body.style.backgroundColor = "#cce5ff";
  else document.body.style.backgroundColor = "#fff8b3";
}

function getSumMessage(sum) {
  if (sum <= 4) return "今日は慎重にいきましょう。";
  if (sum <= 8) return "まずまずの運勢。落ち着いて進めればOK。";
  return "最高の運勢!何をしても楽しめそうです!";
}

function saveHistory(arr) {
  localStorage.setItem("diceHistory", JSON.stringify(arr));
}

function loadHistory() {
  const data = localStorage.getItem("diceHistory");
  return data ? JSON.parse(data) : [];
}

function deleteHistory(index) {
  historyArray.splice(index, 1);
  saveHistory(historyArray);
  renderHistory(historyArray);
}

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>サイコロ1:${item.dice1}</p>
      <p>サイコロ2:${item.dice2}</p>
      <p>合計:${item.sum}</p>
      <p>メッセージ:${item.message}</p>
      <button class="history-delete-btn">削除</button>
    `;

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

    list.appendChild(card);
  });
}

rollBtn.addEventListener("click", function() {
  const n1 = rollDice();
  const n2 = rollDice();
  const sum = n1 + n2;

  dice1.textContent = `サイコロ1:${n1}`;
  dice2.textContent = `サイコロ2:${n2}`;
  diceSum.textContent = `合計:${sum}`;

  updateBackground(sum);
  const msg = getSumMessage(sum);
  diceMessage.textContent = msg;

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

  const historyItem = {
    dice1: n1,
    dice2: n2,
    sum: sum,
    dateTime: dateTimeText,
    message: msg
  };

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

clearHistoryBtn.addEventListener("click", function() {
  localStorage.removeItem("diceHistory");
  historyArray = [];
  renderHistory(historyArray);
});

renderHistory(historyArray);
JavaScript

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

● ローカルストレージは「ブラウザに保存できる小さなデータベース」

  • 配列を JSON にして保存
  • JSON を配列に戻して読み込み
  • ページを閉じてもデータが残る

● DOM操作で「一覧表示」を作れるようになる

  • createElement()
  • appendChild()
  • innerHTML

これらを組み合わせると、 どんなデータでもカードUIにできる。

● イベント処理は「ユーザーの操作に反応する」

  • ボタンを押す → 履歴追加
  • 削除ボタン → 履歴削除
  • 全削除ボタン → 履歴リセット

次のステップ(5日目)

5日目ではさらに一歩進んで、

  • 履歴の並び替え(新しい順・古い順)
  • 履歴の詳細表示
  • カードの色分け・アニメーション削除

という「本格的なサイコロアプリ」へ育てていきます。

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