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);
JavaScript4日目で本当に掴んでほしいこと
● 「データ → 保存 → 画面」の流れがアプリの基本
- データをオブジェクト・配列で管理する
- ローカルストレージに保存する
- DOM操作で画面に反映する
この流れが理解できると、 メモアプリ・TODOアプリ・日記アプリなど、 いろいろなWebアプリに応用できます。
● DOM操作は「画面を再構築する力」
innerHTML = ""で一度消すforEachで配列からカードを作るappendChildで追加する
これが「一覧表示」の基本パターンです。
次の5日目では、 この履歴機能をさらに育てて 並び替え・詳細表示・UI改善 に進んでいきます。


