今回は、HTML/CSS/JavaScriptを使ってシンプルなTODOリストを作成するハンズオン形式の記事です。初心者でも分かりやすい手順で解説します!
完成イメージ
- Todoを入力してリストに追加
- Todoに重要度を設定
- 完了ボタンで項目を削除
htmlの作成
- デスクトップなどにTodoappフォルダを作成する。
- Todoappフォルダの直下に以下のindex.htmlを作成する。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TODO List</title>
<link rel="stylesheet" href="css/main.css">
<script src="js/main.js" defer></script>
</head>
<body>
<h1>TODO List</h1>
<section id="todoContainer">
<label>Todo:<input type="text" id="todoInput" placeholder="Enter todo"></label>
<label>重要度:
<select id="importance">
<option value="5">⭐⭐⭐⭐⭐</option>
<option value="4">⭐⭐⭐⭐</option>
<option value="3" selected>⭐⭐⭐</option>
<option value="2">⭐⭐</option>
<option value="1">⭐️</option>
</select>
</label>
<button id="addItem">追加</button>
</section>
<ul id="todoList"></ul>
</body>
</html>
css/main.css
- Todoappフォルダにcssフォルダを作成しその中にmain.cssを以下のように作成する。
body {
background-color: #f9f9f9;
color: #333;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
}
h1 {
margin: 20px 0;
}
#todoContainer {
margin-bottom: 20px;
}
#todoContainer label {
margin-right: 10px;
}
#todoInput {
padding: 5px;
font-size: 16px;
}
#addItem {
padding: 5px 10px;
font-size: 16px;
}
#todoList {
list-style-type: none;
padding: 0;
width: 98%;
max-width: 460px;
}
#todoList li {
display: flex;
justify-content: flex-start;
align-items: center;
gap:10px;
background-color: #fff;
padding: 10px;
margin-bottom: 5px;
border: 1px solid #ccc;
border-radius: 5px;
}
#todoList li span:first-child {
margin-right:auto;
}
js/main.js
- Todoappフォルダにjsフォルダを作成し、その中にmain.jsを以下のように作成する。
'use strict';
document.addEventListener('DOMContentLoaded', () => {
const todoInput = document.querySelector('#todoInput');
const importance = document.querySelector('#importance');
const bt = document.querySelector('#addItem');
const ul = document.querySelector('#todoList');
let list = [];
bt.addEventListener('click', () => {
const todo = todoInput.value;
const importanceValue = parseInt(importance.value);
const item = { todo, importanceValue };
list.push(item);
todoInput.value = '';
importance.value = "3";
displayList();
});
const finished = (eve) => {
const idx = eve.target.closest('li').dataset.index;
list.splice(idx, 1);
displayList();
};
const displayList = () => {
list.sort((a, b) => b.importanceValue - a.importanceValue);
ul.innerHTML = '';
list.forEach((item, index) => {
const li = document.createElement('li');
li.dataset.index = index;
const spanTitle = document.createElement('span');
spanTitle.textContent = item.todo;
li.appendChild(spanTitle);
const spanImportance = document.createElement('span');
spanImportance.textContent ="⭐️".repeat(item.importanceValue);
li.appendChild(spanImportance);
const bt1 = document.createElement('button');
bt1.textContent = '完了';
bt1.addEventListener('click', finished);
li.appendChild(bt1);
ul.appendChild(li);
});
};
});
JS解説
コードの基本設定
'use strict';
document.addEventListener('DOMContentLoaded', () => {
const todoInput = document.querySelector('#todoInput');
const importance = document.querySelector('#importance');
const bt = document.querySelector('#addItem');
const ul = document.querySelector('#todoList');
let list = [];
'use strict'
: 厳格モードを使用し、潜在的なバグを防ぎます。DOMContentLoaded
: HTMLの読み込みが完了したらスクリプトを実行するように設定。DOM要素が利用可能になるタイミングを確実にします。querySelector
: 各HTML要素(入力欄、重要度セレクト、追加ボタン、リストコンテナ)を取得しています。list
: タスクを保持する配列。この配列を操作してリストの状態を管理します。
タスクの追加機能
bt.addEventListener('click', () => {
const todo = todoInput.value;
const importanceValue = parseInt(importance.value);
const item = { todo, importanceValue };
list.push(item);
todoInput.value = '';
importance.value = "3";
displayList();
});
addEventListener('click')
: 追加ボタンがクリックされたときにタスクを追加する処理を実行。todoInput.value
: 入力されたタスクの内容を取得。importance.value
: 選択された重要度の値を取得し、数値型に変換(parseInt
)。list.push(item)
: 新しいタスクオブジェクト(item
)を配列list
に追加。todoInput.value = ''
: 入力欄をリセット。importance.value = "3"
: 重要度をデフォルト(3
)にリセット。displayList()
: 変更されたタスクリストを画面に表示する関数を呼び出し。
タスク削除機能
const finished = (eve) => {
const idx = eve.target.closest('li').dataset.index;
list.splice(idx, 1);
displayList();
};
finished
関数: タスク削除を担当する関数。eve.target.closest('li')
: クリックされた「完了」ボタンの親要素(<li>
)を取得。dataset.index
: タスクのインデックス(HTMLのdata-index
属性)を取得。list.splice(idx, 1)
: 指定されたインデックスのタスクを配列list
から削除。displayList()
: 変更されたタスクリストを再表示。
リストの表示機能
const displayList = () => {
list.sort((a, b) => b.importanceValue - a.importanceValue);
ul.innerHTML = '';
list.forEach((item, index) => {
const li = document.createElement('li');
li.dataset.index = index;
const spanTitle = document.createElement('span');
spanTitle.textContent = item.todo;
li.appendChild(spanTitle);
const spanImportance = document.createElement('span');
spanImportance.textContent = "⭐️".repeat(item.importanceValue);
li.appendChild(spanImportance);
const bt1 = document.createElement('button');
bt1.textContent = '完了';
bt1.addEventListener('click', finished);
li.appendChild(bt1);
ul.appendChild(li);
});
};
list.sort
: タスクの重要度に基づいて配列をソート(降順)。ul.innerHTML = ''
: リストの中身をクリアし、最新の状態を再描画できるように準備。list.forEach
: 各タスクに対して以下の処理を実行。document.createElement('li')
: 新しいリスト項目(<li>
)を作成。li.dataset.index
: 配列のインデックスをdata-index
属性に設定。spanTitle
: タスク名を表示する<span>
を作成し、リスト項目に追加。spanImportance
: 重要度(星の数)を表示する<span>
を作成し、リスト項目に追加。bt1
: 「完了」ボタンを作成し、削除処理(finished
関数)をバインド。ul.appendChild(li)
: 作成したリスト項目をリストコンテナに追加。
コード全体のポイント
- データ管理: タスクリストの状態を
list
配列で管理し、タスクの追加・削除・表示を効率的に実現。 - イベントリスナー: ユーザーの操作(クリック)を監視し、動的にDOMを更新。
- 動的なHTML生成: JavaScriptを用いてDOM要素を生成・操作し、リアルタイムでリストを更新。
- 重要度の視覚化: 星(⭐️)の数でタスクの重要度を直感的に表示。
データの永続化
現状のままだと、ブラウザをリロードするとすべてのデータが消えてしまう。
localStorageを使ってデータの永続化しよう。
main.jsの変更
main.jsを以下のように変更する。
'use strict';
document.addEventListener('DOMContentLoaded', () => {
const todoInput = document.querySelector('#todoInput');
const importance = document.querySelector('#importance');
const bt = document.querySelector('#addItem');
const ul = document.querySelector('#todoList');
let list = JSON.parse(localStorage.getItem('todoList')) || [];
bt.addEventListener('click', () => {
const todo = todoInput.value;
const importanceValue = parseInt(importance.value);
const item = { todo, importanceValue };
list.push(item);
saveToLocalStorage();
todoInput.value = '';
importance.value = "3";
displayList();
});
const finished = (eve) => {
const idx = eve.target.closest('li').dataset.index;
list.splice(idx, 1);
saveToLocalStorage();
displayList();
};
const displayList = () => {
list.sort((a, b) => b.importanceValue - a.importanceValue);
ul.innerHTML = '';
list.forEach((item, index) => {
const li = document.createElement('li');
li.dataset.index = index;
const spanTitle = document.createElement('span');
spanTitle.textContent = item.todo;
li.appendChild(spanTitle);
const spanImportance = document.createElement('span');
spanImportance.textContent ="⭐️".repeat(item.importanceValue);
li.appendChild(spanImportance);
const bt1 = document.createElement('button');
bt1.textContent = '完了';
bt1.addEventListener('click', finished);
li.appendChild(bt1);
ul.appendChild(li);
});
};
//ローカルストレージへの保存
const saveToLocalStorage=()=>{
localStorage.setItem('todoList',JSON.stringify(list));
};
//初期表示
displayList();
});
変更点の解説
let list = JSON.parse(localStorage.getItem('todoList')) || [];
ローカルストレージからのデータ読み込み
localStorage.getItem('todoList')
: ローカルストレージからデータを取得。JSON.parse
: JSON文字列をJavaScriptのオブジェクト(または配列)に変換。- ローカルストレージにデータがない場合は空配列(
[]
)を初期値として設定。
ローカルストレージへの保存
const saveToLocalStorage = () => {
localStorage.setItem('todoList', JSON.stringify(list));
};
JSON.stringify
: 配列list
をJSON形式の文字列に変換。localStorage.setItem('todoList', ...)
: 変換したデータをローカルストレージに保存。
動作確認
- タスクを追加すると、ローカルストレージに保存されます。
- タスクを削除しても、ローカルストレージが更新されます。
- ページをリロードしても、保存されたタスクが表示されます。
これでデータの永続化が可能になり、ユーザーの利便性が向上します!
コメント