こんにちは。KOUKIです。
本記事は、Udemyの「50 Projects In 50 Days – HTML, CSS & JavaScript」で学習したことを載せています。
<目次>
実装するもの
今回は、フロントサイドをToDoリストアプリを実装します。加えて、バックエンドをGo言語で作成して、データのやりとりをしてみましょう。プチ連携です。
demoは「こちら」で確認できます。
Todoアプリの仕様
2. Todoをクリックすることで、Task完了となる
3. Todoを右クリックするとタスクが消える
パソコンからじゃないと使えないかもですね。
環境構築
簡単な環境構築をお願いします。
必要なファイルは、以下の通りです。
1 2 3 4 5 6 |
$ tree . ├── index.html ├── script.js └── style.css |
CSS版
ページ(HTML)の作成
最初にページを作成しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="style.css" /> <title>Todo List</title> </head> <body> <h1>todos</h1> <form id="form"> <input type="text" class="input" id="input" placeholder="Enter your todo" autocomplete="off"> <ul class="todos" id="todos"></ul> </form> <small>Left click to toggle completed. <br> Right click to delete todo</small> <script src="script.js"></script> </body> </html> |
このHTMLをブラウザ上で表示すると以下のようになります。

スタイル(CSS)を装飾
次は、ページにスタイルをつけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap'); * { box-sizing: border-box; } body { background-color: #f5f5f5; color: #444; font-family: 'Poppins', sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; margin: 0; } h1 { color: rgb(179, 131, 226); font-size: 10rem; text-align: center; opacity: 0.4; } form { box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); max-width: 100%; width: 400px; } .input { border: none; color: #444; font-size: 2rem; padding: 1rem 2rem; display: block; width: 100%; } .input::placeholder { color: #d5d5d5; } .input:focus { outline-color: rgb(179, 131, 226); } .todos { background-color: #fff; padding: 0; margin: 0; list-style-type: none; } .todos li { border-top: 1px solid #e5e5e5; cursor: pointer; font-size: 1.5rem; padding: 1rem 2rem; } .todos li.completed { color: #b6b6b6; text-decoration: line-through; } small { color: #b5b5b5; margin-top: 3rem; text-align: center; } |
ここまで実装すると以下のようになります。

JavaScriptの実装
今回は、フロントエンドで全て完結するアプリケーションを一旦作成します。
そして、次の記事でバックエンド側を作成したら、それに合わせてJavaScriptの処理を変更します。
要素を取得する
最初に、画面操作に必要な要素を取得します。
1 2 3 4 |
// 要素の取得 const form = document.getElementById('form') const input = document.getElementById('input') const todosUL = document.getElementById('todos') |
データ保存
ページをリロードしても作成したTodoを保持しておかなければなりません。そこで、ローカルストレージを使ってデータを保持します。
ローカルストレージは、任意のデータをブラウザ上で保持できる仕組みです。
ただし、Go言語でバックエンドを作成したらそこにデータを持たせるため、不要になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// ローカルストレージからデータを取得 const todos = JSON.parse(localStorage.getItem('todos')) // ローカルストレージ更新 function updateLS() { // li要素を取得 todosEl = document.querySelectorAll('li') // 保存データ const todos = [] todosEl.forEach(todoEl => { // オブジェクトを配列にpush todos.push({ text: todoEl.innerText, completed: todoEl.classList.contains('completed') }) }) // ローカルストレージにtodosキーで保存保存 localStorage.setItem('todos', JSON.stringify(todos)) } |
ローカルストレージにデータを保存したい場合は、localStorage.setItemを使います。第一引数にkeyとして任意の文字列を、第二引数に保存したいデータをそれぞれ指定します。JSONデータも保存できるので、かなり便利ですよね。
JSON.stringifyは、JavaScriptのオブジェクトや値をJSONに変換してくれる便利メソッドです。
逆に取り出すときは、localStorage.getItemを使います。引数には、ローカルストレージに保存した時のキー(todos)を指定します。
completedは、CSSのクラスです。classList.containsでこのクラスが存在するかチェックし、true/falseの値を返します。このクラスが付与されたTodoは完了扱いになります。
Todo作成イベントの発火
Todoを入力した時、submitイベントを発火させ、Todoを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 |
// Todo入力時に発火する form.addEventListener('submit', (e) => { // デフォルトの動きをキャンセル e.preventDefault() // Todoを作成 addTodo() }) function addTodo(todo) { ... } |
preventDefaultは、HTML要素が元々持っているデフォルトの挙動をキャンセルします。ここでは、submitした時にページがリダイレクトされてしまうので、それを防いでいます。
Todo作成
Todoを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
// Todo作成 function addTodo(todo) { // 入力文字を取得 let todoText = input.value if(todo) { todoText = todo.text } if(todoText) { // liリストを作成 const todoEl = document.createElement('li') // タスク完了かチェック // todoはオブジェクトを格納でき、completedを持っている if(todo && todo.completed) { // completedクラスをつける todoEl.classList.add('completed') } todoEl.innerText = todoText // Todoをクリックした時に発火 todoEl.addEventListener('click', () => { // completedクラスがついてたら削除、そうでない場合は付与 todoEl.classList.toggle('completed') // ローカルストレージを更新 updateLS() }) // 右クリックした時に発火するイベント todoEl.addEventListener('contextmenu', (e) => { // デフォルトの動きをキャンセル e.preventDefault() // Todo削除 todoEl.remove() // ローカルストレージを更新 updateLS() }) // Todoを親要素の子要素として追加 todosUL.appendChild(todoEl) // 入力欄をクリア input.value = '' // ローカルストレージを更新 updateLS() } } |
基本的には、コメントに書いてある通りです。
contextmenu属性は、右クリックを押した時にイベントを発火させます。
Todoデータの読み込み
最後に、ページを開いた時にTodoリストを作成するようにします。
1 2 3 4 5 6 |
// ローカルストレージからデータを取得 ... // 画面を開いた時にリストを生成する if(todos) { todos.forEach(todo => addTodo(todo)) } |
これで、完成です。
おわりに
今回のTodoリストは、Todo作成、完了、削除の3つの機能しかありませんが、更新があると更に便利そうですね。時間に余裕があれば、作成してみてください。
次回
次回は、バックエンド側の処理を実装します。
関連記事
こちらの記事も人気です!
JavaScriptまとめ
JavaScript ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
// 要素の取得 const form = document.getElementById('form') const input = document.getElementById('input') const todosUL = document.getElementById('todos') // ローカルストレージからデータを取得 const todos = JSON.parse(localStorage.getItem('todos')) // 画面を開いた時にリストを生成する if(todos) { todos.forEach(todo => addTodo(todo)) } // Todo入力時に発火する form.addEventListener('submit', (e) => { // デフォルトの動きをキャンセル e.preventDefault() // Todoを作成 addTodo() }) // Todo作成 function addTodo(todo) { // 入力文字を取得 let todoText = input.value if(todo) { todoText = todo.text } if(todoText) { // liリストを作成 const todoEl = document.createElement('li') // タスク完了かチェック // todoはオブジェクトを格納でき、completedを持っている if(todo && todo.completed) { // completedクラスをつける todoEl.classList.add('completed') } todoEl.innerText = todoText // Todoをクリックした時に発火 todoEl.addEventListener('click', () => { // completedクラスがついてたら削除、そうでない場合は付与 todoEl.classList.toggle('completed') // ローカルストレージを更新 updateLS() }) // 右クリックした時に発火するイベント todoEl.addEventListener('contextmenu', (e) => { // デフォルトの動きをキャンセル e.preventDefault() // Todo削除 todoEl.remove() // ローカルストレージを更新 updateLS() }) // Todoを親要素の子要素として追加 todosUL.appendChild(todoEl) // 入力欄をクリア input.value = '' // ローカルストレージを更新 updateLS() } } // ローカルストレージ更新 function updateLS() { // li要素を取得 todosEl = document.querySelectorAll('li') // 保存データ const todos = [] todosEl.forEach(todoEl => { // オブジェクトを配列にpush todos.push({ text: todoEl.innerText, completed: todoEl.classList.contains('completed') }) }) // ローカルストレージにtodosキーで保存保存 localStorage.setItem('todos', JSON.stringify(todos)) } |
コメントを残す
コメントを投稿するにはログインしてください。