JavaScriptで作るTodoリスト

JavaScript

今回は、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): 作成したリスト項目をリストコンテナに追加。

コード全体のポイント

  1. データ管理: タスクリストの状態をlist配列で管理し、タスクの追加・削除・表示を効率的に実現。
  2. イベントリスナー: ユーザーの操作(クリック)を監視し、動的にDOMを更新。
  3. 動的なHTML生成: JavaScriptを用いてDOM要素を生成・操作し、リアルタイムでリストを更新。
  4. 重要度の視覚化: 星(⭐️)の数でタスクの重要度を直感的に表示。

データの永続化

現状のままだと、ブラウザをリロードするとすべてのデータが消えてしまう。
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', ...): 変換したデータをローカルストレージに保存。

動作確認

  1. タスクを追加すると、ローカルストレージに保存されます。
  2. タスクを削除しても、ローカルストレージが更新されます。
  3. ページをリロードしても、保存されたタスクが表示されます。

これでデータの永続化が可能になり、ユーザーの利便性が向上します!

関連記事

コメント

タイトルとURLをコピーしました