JavaScript | 1 日 90 分 × 7 日アプリ学習:DOM・イベント・ブラウザUI ToDoアプリ編

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

ToDoアプリ 1日目のゴール

1日目のテーマは 「JavaScriptでブラウザの画面(DOM)を直接さわって、シンプルなToDoリストを動かす」 ことです。

重点として挙がっている

  • querySelector() / querySelectorAll()
  • addEventListener()
  • createElement() / append() / remove()
  • classList
  • dataset

を、実際に動くToDoアプリの中で全部使ってみることを目標にします。

まずは完成イメージを言葉でつかむ

1日目で作るのは、こんな感じの超シンプルなToDoアプリです。

  • 上に「やること」を入力するテキストボックス
  • その横に「追加」ボタン
  • 下に「ToDo一覧」が並ぶ
  • 各ToDoには「削除」ボタンが付いていて、押すとそのToDoだけ消える

まだ「完了チェック」や「並び替え」はやりません。 DOM操作の基本を体に入れることが目的なので、 機能は最小限に絞ります。

HTMLを用意する(JavaScriptがさわる“土台”)

まずは、JavaScriptから操作しやすいように、 シンプルなHTMLを用意します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>ToDoアプリ 1日目</title>
</head>
<body>
  <h1>ToDoアプリ(1日目)</h1>

  <!-- 新しいToDoを入力するフォーム -->
  <div>
    <label for="todoInput">やること:</label>
    <input id="todoInput" type="text" placeholder="やることを入力してください">
    <button id="addButton">追加</button>
  </div>

  <!-- エラーメッセージを表示する場所 -->
  <p id="errorMessage" style="color: red;"></p>

  <!-- ToDo一覧を表示する場所 -->
  <h2>ToDo一覧</h2>
  <ul id="todoList"></ul>

  <script>
    // ここに JavaScript を書いていきます
  </script>
</body>
</html>

ここで押さえておきたいポイント

  • id="todoInput"id="addButton" のように、 JavaScriptから探しやすい“目印”を付けておくことが大事です。
  • ul id="todoList" は、あとで createElement()append() を使って <li> をどんどん追加していく「入れ物」になります。

querySelector() でDOM要素をつかまえる

JavaScriptからHTMLの要素を操作するには、 まず「その要素を変数としてつかまえる」必要があります。 そこで使うのが querySelector() です。

// 入力欄・ボタン・表示エリアなどのDOM要素を取得する
const todoInput = document.querySelector("#todoInput");     // idがtodoInputの要素
const addButton = document.querySelector("#addButton");     // idがaddButtonの要素
const errorMessage = document.querySelector("#errorMessage"); // idがerrorMessageの要素
const todoList = document.querySelector("#todoList");       // idがtodoListの要素
JavaScript

深掘り:querySelector() の考え方

  • querySelector() は「CSSセレクタで1つだけ要素を取ってくる」関数です。
    • "#todoInput"id="todoInput" の要素
    • ".item"class="item" の要素
    • "ul li"ul の中の最初の li
  • 「CSSで指定するのと同じ書き方で、JavaScriptから要素を探せる」と覚えるとスムーズです。

addEventListener() で「ボタンが押された瞬間」をつかまえる

次に、「追加」ボタンがクリックされたときに JavaScriptの処理を動かすために addEventListener() を使います。

// 「追加」ボタンがクリックされたときの処理を登録する
addButton.addEventListener("click", function() {
  // ここに「追加ボタンが押されたときにやりたいこと」を書く
  const text = todoInput.value; // 入力欄の中身を取り出す

  // 入力が空ならエラーを表示して終わり
  if (text.trim() === "") {
    errorMessage.textContent = "やることが入力されていません。";
    return; // 処理をここで止める
  }

  // エラーメッセージを消す
  errorMessage.textContent = "";

  // 新しいToDoを画面に追加する(あとで関数に分ける)
  addTodoItem(text);

  // 入力欄を空にする
  todoInput.value = "";
});
JavaScript

深掘り:addEventListener() の重要な感覚

  • addEventListener("click", function() { ... })「クリックされたら、この関数を呼んでね」とブラウザにお願いするイメージです。
  • イベントの種類は "click" のほかにも "input""change""submit" などたくさんありますが、 まずは "click" をしっかり体に入れるのがおすすめです。

createElement() と append() で新しいToDoを追加する

「追加」ボタンが押されたときに呼び出す addTodoItem() 関数を作っていきます。

// 新しいToDoを画面に追加する関数
function addTodoItem(text) {
  // <li> 要素を新しく作る
  const li = document.createElement("li");

  // ToDoのテキスト部分の <span> を作る
  const span = document.createElement("span");
  span.textContent = text; // ユーザーが入力した文字を表示する

  // 削除ボタンを作る
  const deleteButton = document.createElement("button");
  deleteButton.textContent = "削除";

  // 削除ボタンがクリックされたときに、このToDoを消す処理を登録する
  deleteButton.addEventListener("click", function() {
    // li(このToDoの行)を削除する
    li.remove();
  });

  // liの中に、テキストと削除ボタンを入れる
  li.append(span);
  li.append(deleteButton);

  // 作ったliを、ul(todoList)の中に追加する
  todoList.append(li);
}
JavaScript

深掘り:createElement() / append() / remove()

  • document.createElement("li") → 「まだ画面には出ていないけれど、li要素を1つ作る」
  • li.append(span) → 「liの“子ども”としてspanを追加する」
  • todoList.append(li) → 「ulの中にliを追加する」
  • li.remove() → 「liを親から切り離して、画面から消す」

ここで大事なのは、 「HTMLを直接書き換えるのではなく、JavaScriptで“要素を作って”“親にぶら下げて”“必要になったら消す”」 という流れを体で覚えることです。

classList で見た目や状態を切り替える準備をする

1日目では「完了フラグ」までは作りませんが、 classList の使い方を体験しておくために、 「完了っぽい見た目にするクラス」を付けたり外したりする 小さな例を入れておきます。

まず、CSSクラス名だけ決めておきます(スタイルは後日でもOK)。

<!-- bodyの中に、あとでCSSを足す前提でクラス名だけ決めておく -->
<style>
  .done {
    text-decoration: line-through; /* 完了したタスクっぽく、取り消し線を付ける */
    color: gray;
  }
</style>

次に、addTodoItem() の中で 「クリックしたら完了状態をトグルする」処理を追加します。

function addTodoItem(text) {
  const li = document.createElement("li");

  const span = document.createElement("span");
  span.textContent = text;

  // 完了状態を切り替えるためのクリックイベント
  span.addEventListener("click", function() {
    // classList.toggle() で、doneクラスを付けたり外したりする
    li.classList.toggle("done");
  });

  const deleteButton = document.createElement("button");
  deleteButton.textContent = "削除";

  deleteButton.addEventListener("click", function() {
    li.remove();
  });

  li.append(span);
  li.append(deleteButton);

  todoList.append(li);
}
JavaScript

深掘り:classList の感覚

  • li.classList.add("done")class="done" を付ける(既存のクラスがあればその中に追加される)
  • li.classList.remove("done")class="done" を外す
  • li.classList.toggle("done") → 「付いていなければ付ける」「付いていれば外す」

「状態をクラスで表現する」という考え方は、 UIを作るうえで非常に重要です。 完了・未完了、選択中・非選択、エラー・正常など、 多くの状態をクラスで切り替えることができます。

dataset で「ToDoのID」を持たせる準備をする

1日目の段階では、 「削除ボタンが押されたら、その行を消す」だけで十分ですが、 dataset の使い方を知っておくと、 2日目以降に「配列でToDoを管理する」ときに役立ちます。

ここでは、 各ToDoに「番号(ID)」を持たせる例を見てみましょう。

IDを管理する変数を用意する

// 次に使うToDoのIDを管理する変数
let nextTodoId = 1;
JavaScript

addTodoItem() の中で dataset を使う

function addTodoItem(text) {
  const li = document.createElement("li");

  const span = document.createElement("span");
  span.textContent = text;

  // このToDoのIDをdata-idとして持たせる
  li.dataset.id = String(nextTodoId); // 例: "1", "2", "3" ...

  // IDを1つ進めておく
  nextTodoId = nextTodoId + 1;

  span.addEventListener("click", function() {
    li.classList.toggle("done");
  });

  const deleteButton = document.createElement("button");
  deleteButton.textContent = "削除";

  deleteButton.addEventListener("click", function() {
    // ここで dataset を使ってIDを参照できる
    const id = li.dataset.id; // 例: "1"
    console.log("削除するToDoのID:", id);

    li.remove();
  });

  li.append(span);
  li.append(deleteButton);

  todoList.append(li);
}
JavaScript

深掘り:dataset の意味

  • li.dataset.id = "1" とすると、HTML上では <li data-id="1">...</li> のような形になります。
  • dataset は「data- から始まる属性を、JavaScriptから簡単に扱うための仕組み」です。
  • 配列やオブジェクトと組み合わせると、 「画面上の要素」と「JavaScriptのデータ」を IDで結びつけることができるようになります。

querySelectorAll() の使いどころを軽く体験する

1日目のToDoアプリでは、 querySelectorAll() を使う場面は少ないですが、 「全部のToDoに対して何かしたい」という例を 小さく入れておきます。

例えば、 「全部のToDoを完了状態にする」ボタンを追加してみましょう。

HTMLにボタンを追加

<button id="completeAllButton">全部完了にする</button>

JavaScriptで querySelectorAll() を使う

const completeAllButton = document.querySelector("#completeAllButton");

completeAllButton.addEventListener("click", function() {
  // todoListの中にある全てのliを取得する
  const allItems = document.querySelectorAll("#todoList li");

  // NodeList(配列っぽいもの)をforEachで回す
  allItems.forEach(function(li) {
    li.classList.add("done"); // 全部にdoneクラスを付ける
  });
});
JavaScript

深掘り:querySelectorAll() の感覚

  • querySelectorAll() は「条件に合う要素を全部取ってくる」関数です。
  • 戻り値は「NodeList」という、配列に似たオブジェクトで、 forEach() が使えます。
  • 「一覧の全部に対して何かしたい」ときに使う、と覚えておくとよいです。

1日目の完成コード(まとめ)

ここまでの内容をひとつにまとめた、 ToDoアプリ 1日目の完成版です。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>ToDoアプリ 1日目</title>
  <style>
    .done {
      text-decoration: line-through;
      color: gray;
    }
  </style>
</head>
<body>
  <h1>ToDoアプリ(1日目)</h1>

  <div>
    <label for="todoInput">やること:</label>
    <input id="todoInput" type="text" placeholder="やることを入力してください">
    <button id="addButton">追加</button>
  </div>

  <p id="errorMessage" style="color: red;"></p>

  <div>
    <button id="completeAllButton">全部完了にする</button>
  </div>

  <h2>ToDo一覧</h2>
  <ul id="todoList"></ul>

  <script>
    // --- 状態管理用の変数 ---
    let nextTodoId = 1; // 次に使うToDoのID

    // --- DOM要素の取得 ---
    const todoInput = document.querySelector("#todoInput");
    const addButton = document.querySelector("#addButton");
    const errorMessage = document.querySelector("#errorMessage");
    const todoList = document.querySelector("#todoList");
    const completeAllButton = document.querySelector("#completeAllButton");

    // --- ToDoを追加する関数 ---
    function addTodoItem(text) {
      const li = document.createElement("li");

      const span = document.createElement("span");
      span.textContent = text;

      // このToDoのIDをdata-idとして持たせる
      li.dataset.id = String(nextTodoId);
      nextTodoId = nextTodoId + 1;

      // テキスト部分をクリックしたら完了状態を切り替える
      span.addEventListener("click", function() {
        li.classList.toggle("done");
      });

      const deleteButton = document.createElement("button");
      deleteButton.textContent = "削除";

      // 削除ボタンがクリックされたら、この行を削除する
      deleteButton.addEventListener("click", function() {
        const id = li.dataset.id;
        console.log("削除するToDoのID:", id);
        li.remove();
      });

      li.append(span);
      li.append(deleteButton);

      todoList.append(li);
    }

    // --- 「追加」ボタンのイベント ---
    addButton.addEventListener("click", function() {
      const text = todoInput.value;

      errorMessage.textContent = "";

      if (text.trim() === "") {
        errorMessage.textContent = "やることが入力されていません。";
        return;
      }

      addTodoItem(text);

      todoInput.value = "";
    });

    // --- 「全部完了にする」ボタンのイベント ---
    completeAllButton.addEventListener("click", function() {
      const allItems = document.querySelectorAll("#todoList li");

      allItems.forEach(function(li) {
        li.classList.add("done");
      });
    });
  </script>
</body>
</html>

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

  • DOMは「JavaScriptからさわれる“画面の木構造”」である
    • querySelector() / querySelectorAll() で「木の中の部品」を探す
    • createElement() / append() / remove() で「枝を増やしたり、切ったり」する
  • イベントは「ユーザーの操作に反応するための“きっかけ”」である
    • addEventListener("click", ...) で「クリックされた瞬間」をつかまえる
  • classList と dataset は「状態」と「ID」を表現するための道具
    • classList.toggle("done") で「完了/未完了」を切り替える
    • dataset.id で「この要素は何番のToDoか」を覚えさせる

この1日目を終えた時点で、 読者のみなさんはすでに 「ブラウザの画面をJavaScriptで動かす」という とても大きな一歩を踏み出しています。

2日目以降は、

  • ToDoを配列で管理する
  • フィルタ(未完了だけ表示など)を作る
  • UIを少しずつ整える

といった方向に進みながら、 DOM・イベント・配列・オブジェクトを つなげていく練習をしていきましょう。

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