7日目のゴールと全体像
おみくじアプリ 7日目のテーマは 「6日間で積み上げてきた機能を“完成版”として整理し、アプリ全体の構造を理解しながら総復習すること」 です。
ここまでで、みなさんは
- ランダム結果の生成
- 結果ごとのメッセージ・背景色・ラッキーアイテム
- 履歴保存(ローカルストレージ)
- 履歴一覧表示・削除
- 並び替え(新しい順・古い順)
- 詳細表示
- メモ編集
- カード色分け
- 削除アニメーション
という、初級者が学ぶべき JavaScript の基礎をすべて体験 してきました。
7日目では、これらを ひとつの完成したアプリとしてまとめる ことで、 「JavaScript初級者から Webアプリを作れる人」へステップアップします。
アプリ全体の構造を理解する
完成版のおみくじアプリは、次の3つのレイヤーで構成されています。
● HTML(画面の骨格)
- ボタン
- 結果表示エリア
- メッセージ表示エリア
- ラッキーアイテム表示エリア
- 履歴一覧
- 詳細表示エリア
● CSS(見た目・アニメーション)
- 結果の色分け
- 背景色変更
- 履歴カードのデザイン
- 削除アニメーション
- 詳細カードのデザイン
● JavaScript(動き・データ管理)
- ランダム処理
- DOM操作
- イベント処理
- ローカルストレージ
- 履歴管理(追加・削除・編集)
- 並び替え
- 詳細表示
この3つが組み合わさることで、 「入力 → 計算 → 表示 → 保存 → 編集 → 削除」 という一連の流れが成立します。
完成版HTML(最終形)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>おみくじアプリ 完成版</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>
<button id="sortNewBtn">新しい順</button>
<button id="sortOldBtn">古い順</button>
<div id="historyList"></div>
<button id="clearHistoryBtn">履歴をすべて削除</button>
<h3>詳細</h3>
<div id="detailBox"></div>
<script src="script.js"></script>
</body>
</html>
完成版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: 12px;
margin: 10px 0;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
transition: transform 0.2s, opacity 0.4s;
}
.history-card:hover {
transform: scale(1.02);
}
.fade-out {
opacity: 0;
transform: translateY(-10px);
}
.detail-card {
background: #fefefe;
padding: 15px;
margin-top: 15px;
border: 1px solid #ddd;
border-radius: 8px;
}
完成版JavaScript(最終形)
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);
JavaScript7日目で本当に掴んでほしいこと
● JavaScriptの基礎が「ひとつのアプリ」で全部つながった
- 変数
- 条件分岐
- 繰り返し
- 関数
- DOM操作
- イベント処理
- ローカルストレージ
これらがすべて「おみくじアプリ」という具体的な形の中で自然につながっています。
● Webアプリは「画面 × 動き × データ」でできている
- HTML → 画面
- CSS → 見た目
- JavaScript → 動き・データ管理
この3つを組み合わせることで、 どんなWebアプリでも作れるようになります。
● DOM操作はアプリの“手足”
カード追加、削除、編集、アニメーションなど、 DOMを自在に扱えるとアプリが一気に本格的になる。
次のステップ(応用編への橋)
このおみくじアプリはまだまだ育てられます。
- 結果の統計(大吉の割合など)
- グラフ表示(結果の推移)
- 履歴のCSVダウンロード
- Webアプリ化(React / Vue)
初級編を終えたみなさんは、 もう 「JavaScriptで実用的なWebアプリを作れる人」 です。


