前回は、フォームに入力された文字列を配列(todos)に追加するところまでを確認した。今回は、その配列の中身を実際に画面上のリストとして表示し、さらに「完了チェック」と「削除」の機能を追加していくことにしよう。
1. style.css(CSSファイル)の変更点
HTMLファイルは前回と変わらない。ul#todo-listの中身を、これからJavaScriptで生成していく。CSSには、完了したタスクの見た目を変えるためのクラスを追加しておこう。
style.css(CSSファイル)追加分
.completed {
text-decoration: line-through;
color: #999;
}
li {
display: flex;
align-items: center;
gap: 8px;
list-style: none;
padding: 4px 0;
}style.cssの末尾にこの内容を追加しておこう。
2. script.js(JavaScriptファイル)はまるごと置換
前回のコードに、リストを描画するrenderTodos()という関数を追加する形で拡張していく。
ファイルの中身を、以下の内容にまるごと置き換えてほしい。
script.js(JavaScriptファイル)
// フォームとリストの要素を取得する
const form = document.getElementById('todo-form');
const input = document.getElementById('todo-input');
const list = document.getElementById('todo-list');
// ToDoを保持しておく配列
// 前回は文字列だけの配列だったが、今回からオブジェクトの配列に変更する
const todos = [];
// リストを画面に描画する関数
function renderTodos() {
// 一旦リストを空にしてから作り直す
list.innerHTML = '';
todos.forEach((todo, index) => {
const li = document.createElement('li');
li.innerHTML = `
<input type="checkbox" ${todo.done ? 'checked' : ''}>
<span class="${todo.done ? 'completed' : ''}">${todo.text}</span>
<button>削除</button>
`;
// チェックボックスがクリックされたときの処理
const checkbox = li.querySelector('input');
checkbox.addEventListener('change', () => {
todo.done = checkbox.checked;
renderTodos();
});
// 削除ボタンがクリックされたときの処理
const deleteButton = li.querySelector('button');
deleteButton.addEventListener('click', () => {
todos.splice(index, 1);
renderTodos();
});
list.appendChild(li);
});
}
// フォームが送信されたときの処理
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (text === '') {
return;
}
// 文字列ではなく、完了状態(done)を持つオブジェクトとして追加する
todos.push({ text: text, done: false });
input.value = '';
renderTodos();
});コピペする際は、コードブロックの中身をそのままscript.jsに貼り付け、上から下まで改行の位置がずれていないか一度見直しておくと安心である。
3. コードの解説
まず、todos配列の中身を、単なる文字列から{ text: '牛乳を買う', done: false }のようなオブジェクトに変更している。タスクの文章(text)だけでなく、完了したかどうか(done)という状態を一緒に持たせる必要が出てきたためである。
renderTodos()は、この配列の中身をもとにリストを丸ごと作り直す関数である。処理の流れとしては、まずlist.innerHTML = ''で中身を一旦空にし、そのあとでtodos.forEach()を使って配列の要素を1つずつ<li>要素に変換し、追加し直している。以前の記事「JavaScriptのきほん「DOM要素の操作」」で紹介したdocument.createElement()の応用である。
li.innerHTMLの部分では、テンプレートリテラルを使ってチェックボックス・タスク名・削除ボタンをまとめてHTMLとして組み立てている。todo.doneがtrueであればchecked属性とcompletedクラスを付け、見た目にも完了状態がわかるようにしている。
テンプレートリテラルの詳しい仕組みについては、以前の記事「JavaScriptのきほん「テンプレートリテラル」」も参考にしてほしい。
チェックボックスのchangeイベントと、削除ボタンのclickイベントには、それぞれリスナーを登録している。チェックボックスが操作されたときはtodo.doneの値を書き換え、削除ボタンが押されたときはArray.prototype.splice()を使って配列から該当の要素を取り除いている。
どちらの処理も、最後にrenderTodos()を呼び直すことで、変更内容を画面に反映させている点がポイントである。
このように「データ(todos配列)を変更したら、必ずrenderTodos()で画面を作り直す」という流れを徹底することで、データと画面の表示内容を常に一致させることができる。
4. 動作確認
入力欄からタスクを追加すると、リストに項目が表示されるはずである。チェックボックスをオンにすると文字に取り消し線が入り、削除ボタンを押すとその項目だけがリストから消えることを確認しておこう。

うまく表示されない場合は、開発者ツールのコンソール(F12キーで開く)にエラーが出ていないかを確認しよう。特にidの綴りのずれや、<script>タグの位置(</body>の直前にあるか)は、つまずきやすいポイントである。
次回は、このtodos配列の内容をlocalStorageに保存し、ページを再読み込みしてもリストが消えないようにする処理を追加する。


コメント