総合プロジェクト:Todo アプリ
最後のレッスンにおめでとうございます!これまでの27レッスンで、変数、関数、配列、DOM、イベント、JSON、非同期プログラミング、クラスなどを学んできました。それらをすべて結びつけて、完全な小さなアプリケーションを構築する時が来ました。このプロジェクトは、学んだすべての集大成となります。
プロジェクト概要
Todo アプリを構築します。シンプルに見えますが、学んだほぼすべてのコアコンCEPTに触れます。完成すれば、実際に使える生産性ツールが手に入ります。
機能要件
- Todo アイテムの追加 — 入力フィールド + ボタン。Enter キーまたはクリックで新しいアイテムを追加
- 完了/未完了のトグル — Todo をクリックして完了状態を切り替え(取り消し線効果)
- Todo アイテムの削除 — 各アイテムに削除ボタンが付いている
- フィルタリング — 3つのボタン:すべて / 未完了 / 完了済み
- ローカルストレージ —
localStorageを使ってページ更新後もデータを永続化 - 残りアイテム数の表示 — 下部に「X 件残っています」と表示
技術要件
| コンCEPT | 使用箇所 |
|---|---|
| クラス | TodoApp クラスですべてのロジックを整理 |
| async/await | localStorage の読み書きを非同期関数でラップ |
| DOM 操作 | リスト項目の動的作成、コンテンツ更新、要素の削除 |
| イベント処理 | フォーム submit、リスト click、フィルタボタン click |
| JSON | JSON.stringify で保存、JSON.parse で読み込み |
| 配列メソッド | filter、map、find で Todo データを管理 |
| テンプレートリテラル | HTML 文字列の構築 |
受入基準
- [ ] 6つの機能すべてが正しく動作する
- [ ] ページ更新後もデータが保持される
- [ ] コードに明確なコメントがある
- [ ]
alert/prompt/confirmを使わず、ページ内のインタラクションを使用 - [ ] 空の入力は拒否される(メッセージ付き)
参考実装アイデア
以下はヒントと方向性です。完全なコードではありません。自分で書くことで本当の学びが得られます。
データ構造
HTML
<script>
// 各 Todo アイテムはオブジェクト
const todo = {
id: Date.now(), // ユニーク識別子
text: 'JavaScript を学ぶ',
completed: false
};
console.log(todo);
// すべての Todo アイテムは配列に格納
let todos = [];
</script>
クラス構造
HTML
<script>
class TodoApp {
constructor() {
this.todos = []; // データ
this.filter = 'all'; // 現在のフィルタ
this.init(); // 初期化
}
async init() {
// 1. localStorage からデータを読み込み
// 2. イベントをバインド
// 3. リストをレンダリング
}
async save() {
// JSON.stringify → localStorage.setItem
}
async load() {
// localStorage.getItem → JSON.parse
}
addTodo(text) { /* オブジェクト作成、push、保存、レンダリング */ }
toggleTodo(id) { /* アイテムを検索、completed を反転、保存、レンダリング */ }
deleteTodo(id) { /* アイテムをフィルタアウト、保存、レンダリング */ }
render() {
// 1. this.filter に基づいて todos をフィルタ
// 2. リストコンテナをクリア
// 3. フィルタされた配列をループし、DOM ノードを作成
// 4. カウント表示を更新
}
}
</script>
イベントバインド戦略
- フォーム
submit:e.preventDefault()→ 入力値を取得 →addTodo(text)→ 入力をクリア - リスト
click(イベント委譲):e.targetがトグルまたは削除ボタンかを確認 → 適切なメソッドを呼び出し - フィルタボタン
click:this.filterを更新 →render()
レンダリング戦略
HTML
<script>
render() {
const filtered = this.todos.filter(function(todo) {
if (this.filter === 'active') return !todo.completed;
if (this.filter === 'completed') return todo.completed;
return true; // 'all'
}.bind(this));
// コンテナをクリア
this.listEl.innerHTML = '';
filtered.forEach(function(todo) {
var li = document.createElement('li');
// コンテンツ、スタイル、データ属性を設定
// トグルと削除イベントをバインド
this.listEl.appendChild(li);
}.bind(this));
// カウントを更新
var activeCount = this.todos.filter(function(t) { return !t.completed; }).length;
this.countEl.textContent = activeCount + ' 件残っています';
}
</script>
拡張アイデア
基本機能が動作したら、これらの高度なチャレンジに挑戦してみましょう。
- 🔄 ドラッグ&ドロップソート — HTML5 Drag & Drop API またはタッチイベントで実装
- ✏️ 編集 — Todo をダブルクリックして編集モードに入り、Enter で保存
- 🏷️ カテゴリタグ — ラベル(仕事 / 学習 / 生活)を追加し、タグでフィルタ
- 🎨 テーマ切り替え — ダーク/ライトテーマ、
localStorageで永続化 - ⏰ 期限リマインダー — 各アイテムに締め切りを追加、期限超過を赤色でハイライト
課題
上記の Todo アプリをすべての機能を実装し、すべての受入基準をクリアしてください。
推奨ステップ:
- HTML 構造と CSS スタイルから始める
TodoAppクラスのスケルトンを構築(constructor、init)addTodoとrenderを実装。まず追加を動作させるtoggleTodoを実装。完了/未完了の切り替えdeleteTodoを実装。アイテムの削除- フィルタリングを実装
saveとloadを実装。データの永続化- 残りアイテム数の表示
- 最終仕上げ:空入力のバリデーション、スタイルの調整
💡 一度にすべてを構築しようとしないでください。まず最小のものを動作させ、その後1つずつ追加していきましょう。ソフトウェア開発は「動かして、正しくして、速くする」です。
📝 演習
- 基礎:コア Todo 機能を完成させてください。追加、完了トグル、削除を配列を使って実装(
localStorageは不要)。 - 中級:基本版に
localStorageによる永続化とフィルタリング(すべて / 未完了 / 完了済み)を追加してください。ページ更新後もデータが保持されるようにしてください。 - チャレンジ:拡張機能を少なくとも1つ実装してください(ドラッグ&ドロップソート、編集、カテゴリタグ、テーマ切り替え、または期限リマインダー)。アプローチの簡単な説明も書いてください。



