6日目のゴールと全体像
おみくじアプリ 6日目のテーマは 「履歴カードを“編集・色分け・アニメーション付き削除”できるようにし、DOM操作の応用力を一段階引き上げること」 です。
ここまでで、みなさんは
- ランダム結果の表示
- 結果ごとのメッセージ・背景色・ラッキーアイテム
- 履歴保存(ローカルストレージ)
- 履歴一覧表示・削除
- 並び替え・詳細表示
という「小さな占いサービス」のようなアプリを作ってきました。
6日目ではここに 編集機能・色分け・アニメーション を加えて、 より“使いやすく・楽しい”おみくじアプリへ育てます。
履歴カードに「メモ編集」機能を追加する
履歴に「メモ」を追加できると、 自分だけの占い記録帳 として使えるようになります。
履歴オブジェクトに memo を追加する
4日目の履歴オブジェクトに memo を追加します。
const historyItem = {
dateTime: dateTimeText,
time: now.getTime(),
result: randomResult,
rank: data.rank,
luckyItem: item,
memo: "" // 新しく追加
};
JavaScriptメモ編集ボタンをカードに追加する
履歴カードの HTML を拡張します。
card.innerHTML = `
<p>日時:${item.dateTime}</p>
<p>結果:${item.result}(ランク:${item.rank})</p>
<p>ラッキーアイテム:${item.luckyItem}</p>
<p>メモ:${item.memo || "なし"}</p>
<button class="history-detail-btn">詳細を見る</button>
<button class="history-edit-btn">メモ編集</button>
<button class="history-delete-btn">削除</button>
`;
JavaScriptメモ編集処理を作る
function editMemo(index) {
const newMemo = prompt("メモを入力してください:");
if (newMemo === null) return; // キャンセル時
historyArray[index].memo = newMemo; // メモ更新
saveHistory(historyArray); // 保存
renderHistory(historyArray); // 再描画
}
JavaScript深掘りポイント
prompt()は簡易入力ダイアログ- キャンセル時は
nullが返る - 履歴配列の該当 index の memo を書き換えるだけでOK
- 「データ → 保存 → 再描画」の流れが重要
履歴カードを「結果のランク」で色分けする
視覚的にわかりやすくするため、 カードの背景色をランクに応じて変えます。
ランク → 色の例
- rank 5(大吉) → 金色
- rank 4(中吉) → 青
- rank 3(小吉) → 緑
- rank 2(吉) → 紫
- rank 1(末吉) → オレンジ
- rank 0(凶) → 赤
色を返す関数
function getCardColor(rank) {
if (rank === 5) return "#fff8b3";
if (rank === 4) return "#cce5ff";
if (rank === 3) return "#d4edda";
if (rank === 2) return "#e2d4ff";
if (rank === 1) return "#ffe5b4";
return "#f8d7da";
}
JavaScriptカード生成時に色を適用
card.style.backgroundColor = getCardColor(item.rank);
JavaScript削除アニメーションを追加する
削除時にカードがふわっと消えると、 アプリの使い心地が大きく向上します。
CSS(削除アニメーション)
.fade-out {
opacity: 0;
transform: translateY(-10px);
transition: opacity 0.4s, transform 0.4s;
}
JavaScript(削除処理)
function deleteHistory(index, cardElement) {
cardElement.classList.add("fade-out");
setTimeout(() => {
historyArray.splice(index, 1);
saveHistory(historyArray);
renderHistory(historyArray);
}, 400);
}
JavaScript深掘りポイント
.classList.add()でCSSアニメーションを適用setTimeout()でアニメーション後に削除- UIが滑らかになるとアプリの満足度が大きく上がる
6日目の完成コード(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");
let historyArray = loadHistory();
// 結果候補
const results = ["大吉", "中吉", "小吉", "吉", "末吉", "凶"];
// 結果データ
const omikujiData = {
"大吉": { rank: 5, message: "最高の一日になりそうです。" },
"中吉": { rank: 4, message: "良い流れが来ています。" },
"小吉": { rank: 3, message: "少しずつ前に進める日。" },
"吉": { rank: 2, message: "穏やかな一日。" },
"末吉": { rank: 1, message: "準備をしておくと後で役に立ちます。" },
"凶": { rank: 0, message: "慎重に行動してみましょう。" }
};
// ラッキーアイテム
const luckyItems = [
"赤いペン", "お気に入りの本", "コーヒー", "新しいノート",
"青い服", "散歩", "音楽プレイリスト", "ストレッチ", "おいしいお菓子"
];
// ランダム結果
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 getCardColor(rank) {
if (rank === 5) return "#fff8b3";
if (rank === 4) return "#cce5ff";
if (rank === 3) return "#d4edda";
if (rank === 2) return "#e2d4ff";
if (rank === 1) return "#ffe5b4";
return "#f8d7da";
}
// 履歴保存
function saveHistory(arr) {
localStorage.setItem("omikujiHistory", JSON.stringify(arr));
}
// 履歴読み込み
function loadHistory() {
const data = localStorage.getItem("omikujiHistory");
return data ? JSON.parse(data) : [];
}
// メモ編集
function editMemo(index) {
const newMemo = prompt("メモを入力してください:");
if (newMemo === null) return;
historyArray[index].memo = newMemo;
saveHistory(historyArray);
renderHistory(historyArray);
}
// 詳細表示
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>メモ:${item.memo || "なし"}</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.style.backgroundColor = getCardColor(item.rank);
card.innerHTML = `
<p>日時:${item.dateTime}</p>
<p>結果:${item.result}(ランク:${item.rank})</p>
<p>ラッキーアイテム:${item.luckyItem}</p>
<p>メモ:${item.memo || "なし"}</p>
<button class="history-detail-btn">詳細</button>
<button class="history-edit-btn">メモ編集</button>
<button class="history-delete-btn">削除</button>
`;
card.querySelector(".history-detail-btn").addEventListener("click", function() {
showDetail(item);
});
card.querySelector(".history-edit-btn").addEventListener("click", function() {
editMemo(index);
});
card.querySelector(".history-delete-btn").addEventListener("click", function() {
deleteHistory(index, card);
});
list.appendChild(card);
});
}
// 削除(アニメーション付き)
function deleteHistory(index, cardElement) {
cardElement.classList.add("fade-out");
setTimeout(() => {
historyArray.splice(index, 1);
saveHistory(historyArray);
renderHistory(historyArray);
}, 400);
}
// おみくじボタン
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,
memo: ""
};
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);
JavaScript6日目で本当に掴んでほしいこと
● DOM操作は「画面を作り変える力」
カードUI、編集、削除、アニメーションなど、 DOMを自在に扱えるとアプリが一気に本格的になる。
● ローカルストレージ+編集機能で“占い記録帳”になる
履歴が残り、編集できることで、 おみくじアプリは「自分の運勢ログ」に進化する。
● イベント処理は複数組み合わせると強力
- click
- DOM追加
- ローカルストレージ保存
- アニメーション
これらが組み合わさると、 ユーザーが気持ちよく使えるアプリになる。
次のステップ
7日目では、 アプリ全体を完成版として整理し、構造を最終調整する というステップへ進みます。


