ToDoアプリ 1日目のゴール
1日目のテーマは 「JavaScriptでブラウザの画面(DOM)を直接さわって、シンプルなToDoリストを動かす」 ことです。
重点として挙がっている
querySelector()/querySelectorAll()addEventListener()createElement()/append()/remove()classListdataset
を、実際に動く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;
JavaScriptaddTodoItem() の中で 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・イベント・配列・オブジェクトを つなげていく練習をしていきましょう。

