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

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

6日目のゴールと全体像

サイコロアプリ 6日目のテーマは 「履歴カードを“編集・色分け・アニメーション付き削除”できるようにし、DOM操作の応用力をさらに引き上げること」 です。

ここまでで、みなさんは

  • 2つのサイコロを振る
  • 合計値を計算する
  • 合計値に応じて背景色・メッセージを変える
  • 履歴を保存・一覧表示・削除する
  • 並び替え・詳細表示

という「データ管理ができるサイコロアプリ」を作ってきました。

6日目ではここに 編集機能・色分け強化・削除アニメーション を加えて、 より“使いやすく楽しい”アプリへ進化させます。

履歴カードに「メモ編集」機能を追加する

履歴に「メモ」を追加できると、 自分だけのサイコロ記録帳 として使えるようになります。

履歴オブジェクトに memo を追加する

const historyItem = {
  dice1: n1,
  dice2: n2,
  sum: sum,
  dateTime: dateTimeText,
  message: msg,
  memo: "", // 新しく追加
  time: now.getTime()
};
JavaScript

深掘りポイント

  • メモは「ユーザーが自由に書ける情報」。
  • オブジェクトにプロパティを追加するだけで機能拡張できる。
  • データ構造を柔軟に扱えることが JavaScript の強み。

メモ編集ボタンをカードに追加する

card.innerHTML = `
  <p>日時:${item.dateTime}</p>
  <p>サイコロ1:${item.dice1}</p>
  <p>サイコロ2:${item.dice2}</p>
  <p>合計:${item.sum}</p>
  <p>メッセージ:${item.message}</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 が返るため、必ず条件分岐で処理を止める。
  • 「データを更新 → 保存 → 再描画」が一連の流れ。

カード色分け(合計値によって背景色を変える)

合計値が高いほど明るい色にするなど、 視覚的にわかりやすくします。

function getCardColor(sum) {
  if (sum <= 4) return "#f8d7da"; // 赤
  if (sum <= 8) return "#cce5ff"; // 青
  return "#fff8b3";               // 金色
}
JavaScript

深掘りポイント

  • 色分けは「視覚的フィードバック」を強化する。
  • 合計値の強さが直感的に伝わる。
  • UIの質が上がるとアプリの満足度が大きく向上する。

削除アニメーションを追加する

削除時にカードがふわっと消えると、 アプリの使い心地が大きく向上します。

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が滑らかになると「プロっぽいアプリ」になる。

履歴描画関数を強化する

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.sum);

    card.innerHTML = `
      <p>日時:${item.dateTime}</p>
      <p>サイコロ1:${item.dice1}</p>
      <p>サイコロ2:${item.dice2}</p>
      <p>合計:${item.sum}</p>
      <p>メッセージ:${item.message}</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);
  });
}
JavaScript

6日目の完成コード(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");
const sortNewBtn = document.getElementById("sortNewBtn");
const sortOldBtn = document.getElementById("sortOldBtn");

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 getCardColor(sum) {
  if (sum <= 4) return "#f8d7da";
  if (sum <= 8) return "#cce5ff";
  return "#fff8b3";
}

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

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

function showDetail(item) {
  const detailBox = document.getElementById("detailBox");

  detailBox.innerHTML = `
    <div class="detail-card">
      <p>日時:${item.dateTime}</p>
      <p>サイコロ1:${item.dice1}</p>
      <p>サイコロ2:${item.dice2}</p>
      <p>合計:${item.sum}</p>
      <p>メッセージ:${item.message}</p>
      <p>メモ:${item.memo || "なし"}</p>
    </div>
  `;
}

function editMemo(index) {
  const newMemo = prompt("メモを入力してください:");
  if (newMemo === null) return;

  historyArray[index].memo = newMemo;
  saveHistory(historyArray);
  renderHistory(historyArray);
}

function deleteHistory(index, cardElement) {
  cardElement.classList.add("fade-out");

  setTimeout(() => {
    historyArray.splice(index, 1);
    saveHistory(historyArray);
    renderHistory(historyArray);
  }, 400);
}

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.sum);

    card.innerHTML = `
      <p>日時:${item.dateTime}</p>
      <p>サイコロ1:${item.dice1}</p>
      <p>サイコロ2:${item.dice2}</p>
      <p>合計:${item.sum}</p>
      <p>メッセージ:${item.message}</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);
  });
}

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,
    memo: "",
    time: now.getTime()
  };

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

clearHistoryBtn.addEventListener("click", function() {
  localStorage.removeItem("diceHistory");
  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);
JavaScript

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

● DOM操作は「画面を作り変える力」

カードUI、編集、削除、アニメーションなど、 DOMを自在に扱えるとアプリが一気に本格的になる。

● ローカルストレージ+編集機能で“記録アプリ”になる

履歴が残り、編集できることで、 サイコロアプリは「自分の運勢ログ」に進化する。

● イベント処理は複数組み合わせると強力

  • click
  • DOM追加
  • ローカルストレージ保存
  • アニメーション

これらが組み合わさると、 ユーザーが気持ちよく使えるアプリになる。

次のステップ(7日目)

7日目では、 アプリ全体を完成版として整理し、構造を最終調整する というステップへ進みます。

さらに深掘りしたい方は DOM操作の応用イベント処理の設計 を選ぶと理解がより強固になります。

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