5日目のゴールと全体像
おみくじアプリ 5日目のテーマは 「履歴を“並び替え・詳細表示”できるようにして、DOM操作とイベント処理を一段階レベルアップさせること」 です。
ここまでで、
- おみくじ結果をランダムに表示
- 結果ごとにメッセージ・背景色・ラッキーアイテムを表示
- 履歴をローカルストレージに保存
- 履歴をカードとして一覧表示・削除
という「データを扱うおみくじアプリ」の基礎ができました。
5日目ではここに
- 履歴の並び替え(新しい順・古い順)
- 履歴の詳細表示(1件を拡大して表示)
を追加して、 「ちょっとした占いサービス」のようなアプリに近づけていきます。
並び替え機能のイメージと設計
履歴には「日時」が入っています。 これを使って、
- 新しい順(最近引いたものが上)
- 古い順(昔のものが上)
に並び替えられるようにします。
並び替えボタンをHTMLに追加する
<h3>履歴</h3>
<!-- 並び替えボタン -->
<button id="sortNewBtn">新しい順</button>
<button id="sortOldBtn">古い順</button>
<div id="historyList"></div>
<button id="clearHistoryBtn">履歴をすべて削除</button>
押さえておきたいポイント
id="sortNewBtn"とid="sortOldBtn"をJavaScriptから取得して、 クリックイベントを登録します。- 並び替えは「配列の順番を変える」ことで実現します。
並び替えの基本:配列の sort メソッド
JavaScriptの配列には sort() というメソッドがあります。
historyArray.sort((a, b) => b.dateTimeValue - a.dateTimeValue);
JavaScriptのように書くと、 dateTimeValue を基準に並び替えができます。
5日目では、履歴オブジェクトに「数値の時間」を持たせておき、 それを使って並び替えます。
履歴オブジェクトに「time(数値)」を追加する
4日目の履歴オブジェクトはこうでした。
const historyItem = {
dateTime: dateTimeText,
result: randomResult,
rank: data.rank,
luckyItem: item
};
JavaScriptここに「time」を追加します。
const historyItem = {
dateTime: dateTimeText, // 画面表示用の文字列
time: now.getTime(), // 並び替え用の数値(1970年からのミリ秒)
result: randomResult,
rank: data.rank,
luckyItem: item
};
JavaScript深掘りポイント
new Date().getTime()は「1970年1月1日からのミリ秒」を返します。- この数値は「時間が進むほど大きくなる」ので、 並び替えにとても使いやすいです。
- 「人間向けの文字列」と「機械向けの数値」を両方持たせるのは、 実際のアプリでもよくあるパターンです。
並び替えボタンのイベント処理
要素の取得
const sortNewBtn = document.getElementById("sortNewBtn");
const sortOldBtn = document.getElementById("sortOldBtn");
JavaScript新しい順に並び替える処理
sortNewBtn.addEventListener("click", function() {
// timeが大きいもの(新しいもの)を前に
historyArray.sort((a, b) => b.time - a.time);
// 並び替え後の配列を画面に反映
renderHistory(historyArray);
});
JavaScript古い順に並び替える処理
sortOldBtn.addEventListener("click", function() {
// timeが小さいもの(古いもの)を前に
historyArray.sort((a, b) => a.time - b.time);
renderHistory(historyArray);
});
JavaScript深掘りポイント
sort()は「元の配列を並び替える」メソッドです。(a, b) => b.time - a.timeは「比較関数」と呼ばれます。- 結果が正の数 → aよりbが前
- 結果が負の数 → bよりaが前
- 並び替えたら必ず
renderHistory()を呼んで画面を更新します。
詳細表示機能のイメージ
履歴カードをクリックしたときに、 その1件分の情報を「詳細エリア」に表示します。
- 日時
- 結果
- ランク
- ラッキーアイテム
- 簡単なコメント(固定文でもOK)
HTMLに詳細表示エリアを追加する
<h3>詳細</h3>
<div id="detailBox"></div>
詳細表示用の関数を作る
function showDetail(item) {
const detailBox = document.getElementById("detailBox");
detailBox.innerHTML = `
<div class="detail-card">
<p>日時:${item.dateTime}</p>
<p>結果:${item.result}</p>
<p>ランク:${item.rank}</p>
<p>ラッキーアイテム:${item.luckyItem}</p>
<p>コメント:この結果をきっかけに、少しだけいつもと違う行動をしてみると面白いかもしれません。</p>
</div>
`;
}
JavaScriptCSSで詳細カードを整える
.detail-card {
background: #f7f7f7;
padding: 12px;
margin-top: 10px;
border-radius: 6px;
border: 1px solid #ddd;
}
深掘りポイント
- 詳細表示は「1件分のデータを、専用のエリアに描画する」だけ。
itemオブジェクトをそのまま使うことで、 どの履歴をクリックしても同じ関数で表示できる。
履歴カードに「詳細ボタン」を追加する
renderHistory() の中で、 カードに「詳細を見る」ボタンを追加します。
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-detail-btn">詳細を見る</button>
<button class="history-delete-btn">この履歴を削除</button>
`;
const detailBtn = card.querySelector(".history-detail-btn");
detailBtn.addEventListener("click", function() {
showDetail(item);
});
const deleteBtn = card.querySelector(".history-delete-btn");
deleteBtn.addEventListener("click", function() {
deleteHistory(index);
});
list.appendChild(card);
});
}
JavaScript深掘りポイント
showDetail(item)に「その履歴のオブジェクト」を渡している。- こうすることで、詳細表示関数は「どの履歴か」を意識せずに書ける。
- イベント処理の中で「別の関数を呼ぶ」パターンは、 コードを読みやすくするためにとても重要です。
5日目の完成コード(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 sortNewBtn = document.getElementById("sortNewBtn");
const sortOldBtn = document.getElementById("sortOldBtn");
// 結果候補
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 showDetail(item) {
const detailBox = document.getElementById("detailBox");
detailBox.innerHTML = `
<div class="detail-card">
<p>日時:${item.dateTime}</p>
<p>結果:${item.result}</p>
<p>ランク:${item.rank}</p>
<p>ラッキーアイテム:${item.luckyItem}</p>
<p>コメント:この結果をきっかけに、少しだけいつもと違う行動をしてみると面白いかもしれません。</p>
</div>
`;
}
// 履歴描画
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-detail-btn">詳細を見る</button>
<button class="history-delete-btn">この履歴を削除</button>
`;
const detailBtn = card.querySelector(".history-detail-btn");
detailBtn.addEventListener("click", function() {
showDetail(item);
});
const deleteBtn = card.querySelector(".history-delete-btn");
deleteBtn.addEventListener("click", function() {
deleteHistory(index);
});
list.appendChild(card);
});
}
// 履歴削除
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,
time: now.getTime(),
result: randomResult,
rank: data.rank,
luckyItem: item
};
historyArray.push(historyItem);
saveHistory(historyArray);
renderHistory(historyArray);
});
// 全履歴削除
clearHistoryBtn.addEventListener("click", function() {
localStorage.removeItem("omikujiHistory");
historyArray = [];
renderHistory(historyArray);
});
// 並び替え:新しい順
sortNewBtn.addEventListener("click", function() {
historyArray.sort((a, b) => b.time - a.time);
renderHistory(historyArray);
});
// 並び替え:古い順
sortOldBtn.addEventListener("click", function() {
historyArray.sort((a, b) => a.time - b.time);
renderHistory(historyArray);
});
// 初期表示
renderHistory(historyArray);
JavaScript5日目で本当に掴んでほしいこと
- 配列の
sort()を使って「データの順番を変える」感覚 - オブジェクトを渡して「詳細表示」をするパターン
- 「データを変える → 保存する → DOMで画面を更新する」という一連の流れ
ここまで来ると、 おみくじアプリはもう立派な「小さなWebサービス」です。
6日目・7日目では、 このアプリを「完成版」として整理しながら、 JavaScript初級の総復習をしていきます。


