WEBブラウザで動くToDoリストアプリのコード解説(app.js)
前回作成したWEBアプリのコード解説(app.js)です。
- ToDoリストアプリ(1/5)
- ToDoリストアプリ(2/5)
- ToDoリストアプリ(3/5)
- ToDoリストアプリ(4/5)
- ToDoリストアプリ(5/5)
- WEBアプリのURL
- GitHubのURL
GitHubのPagesで公開しているのでToDoリストアプリを使用できます。
コード概要
- ToDoリストアプリケーションのメインJavaScriptファイル
- TaskManagerとUIManagerクラスを使用
- DOMContentLoadedイベントで初期化
- タスク追加、日付選択、カレンダー表示の機能を実装
- フォームのバリデーションとエラー表示を含む
app.jsの解説
インポートと初期設定
// タスク管理とUI管理のクラスをインポート
import { TaskManager } from './taskManager.js';
import { UIManager } from './uiManager.js';
// DOMの読み込みが完了したら実行
document.addEventListener('DOMContentLoaded', () => {
// タスク管理とUI管理のインスタンスを作成
const taskManager = new TaskManager();
const uiManager = new UIManager(taskManager);
- TaskManagerとUIManagerクラスをインポート
- DOMContentLoadedイベントリスナーを設定
- TaskManagerとUIManagerのインスタンスを作成
このコードは、アプリケーションの初期設定を行っています。まず、タスク管理とUI管理のためのクラスをインポートします。次に、DOMContentLoadedイベントリスナーを設定することで、HTMLの読み込みが完了した後にJavaScriptのコードが実行されるようにしています。そして、タスク管理とUI管理のインスタンスを作成し、アプリケーション全体で使用できるようにしています。
HTML要素の取得
// HTML要素の取得
const taskForm = document.getElementById('task-form');
const taskInput = document.getElementById('task-input');
const dateSelectBtn = document.getElementById('date-select-btn');
const selectedDateSpan = document.getElementById('selected-date');
const taskError = document.getElementById('task-error');
const dateError = document.getElementById('date-error');
const customCalendar = document.getElementById('custom-calendar');
- 必要なHTML要素をgetElementByIdメソッドで取得
- 取得した要素を定数に格納
このコードでは、HTMLドキュメント内の特定の要素をJavaScriptから操作するために、getElementByIdメソッドを使用して要素を取得しています。これらの要素は後のコードで頻繁に使用されるため、変数に格納しておくことで、コードの可読性と効率を向上させています。
変数の初期化
// 変数の初期化
let selectedDate = '';
let isCalendarVisible = false;
let currentCalendarDate = new Date();
- selectedDate: 選択された日付を格納
- isCalendarVisible: カレンダーの表示状態を管理
- currentCalendarDate: 現在表示中のカレンダーの日付を管理
これらの変数は、アプリケーションの状態を管理するために使用されます。selectedDateは、ユーザーが選択した日付を保持します。isCalendarVisibleは、カレンダーが表示されているかどうかを示すブール値です。currentCalendarDateは、カレンダーに表示されている現在の月を追跡するために使用されます。
イベントリスナーの設定
// イベントリスナーの設定
taskForm.addEventListener('submit', handleFormSubmit);
dateSelectBtn.addEventListener('click', toggleCalendar);
document.addEventListener('click', handleOutsideClick);
- taskFormにsubmitイベントリスナーを追加
- dateSelectBtnにclickイベントリスナーを追加
- document全体にclickイベントリスナーを追加
このコードでは、ユーザーの操作に応じてアプリケーションが反応するように、各要素にイベントリスナーを設定しています。taskFormのsubmitイベントは新しいタスクの追加を、dateSelectBtnのclickイベントはカレンダーの表示切り替えを、document全体のclickイベントはカレンダー外のクリックを処理します。
フォーム送信時の処理
// フォーム送信時の処理
function handleFormSubmit(e) {
e.preventDefault(); // デフォルトの送信動作を防止
const taskText = taskInput.value.trim(); // 入力されたタスクのテキストを取得
resetErrors(); // エラーメッセージをリセット
// バリデーション
if (!taskText) {
showError(taskError, 'タスクを入力してください');
return;
}
if (!selectedDate) {
showError(dateError, '日付を設定してください');
return;
}
// タスクを追加
uiManager.addTask(taskText, selectedDate);
resetForm(); // フォームをリセット
}
- preventDefaultでデフォルトの送信動作を防止
- 入力値のバリデーションを実行
- エラーがなければタスクを追加し、フォームをリセット
この関数は、フォームが送信されたときに呼び出されます。まず、フォームのデフォルトの送信動作を防止します。次に、入力されたタスクと日付のバリデーションを行い、エラーがあれば表示します。すべてが正常であれば、UIManagerを通じてタスクを追加し、フォームをリセットします。
カレンダーの表示/非表示切り替え
// カレンダーの表示/非表示を切り替え
function toggleCalendar(e) {
e.stopPropagation(); // イベントの伝播を停止
isCalendarVisible ? hideCalendar() : showCalendar();
}
// カレンダーを表示
function showCalendar() {
const rect = dateSelectBtn.getBoundingClientRect();
customCalendar.style.display = 'block';
// カレンダーの位置を設定
customCalendar.style.top = `${rect.bottom + window.scrollY}px`;
customCalendar.style.left = `${rect.left + window.scrollX}px`;
renderCalendar(currentCalendarDate);
isCalendarVisible = true;
}
// カレンダーを非表示
function hideCalendar() {
customCalendar.style.display = 'none';
isCalendarVisible = false;
}
- toggleCalendar: カレンダーの表示/非表示を切り替え
- showCalendar: カレンダーを表示し、位置を設定
- hideCalendar: カレンダーを非表示にする
これらの関数は、カレンダーの表示を制御します。toggleCalendarは、現在の状態に応じてカレンダーの表示/非表示を切り替えます。showCalendarは、カレンダーを表示し、ボタンの位置に基づいて適切な位置に配置します。hideCalendarは、カレンダーを非表示にします。
カレンダーのレンダリング
// カレンダーをレンダリング
function renderCalendar(date) {
const year = date.getFullYear();
const month = date.getMonth();
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
let calendarHTML = createCalendarHeader(year, month);
calendarHTML += createCalendarDays(firstDay, lastDay);
customCalendar.innerHTML = calendarHTML;
addCalendarEventListeners(year, month);
}
- 指定された日付に基づいてカレンダーをレンダリング
- カレンダーのヘッダーと日付部分を生成
- 生成したHTMLをDOMに挿入
- カレンダーの各要素にイベントリスナーを追加
この関数は、指定された日付に基づいてカレンダーを生成し、表示します。まず、カレンダーのヘッダー部分と日付部分のHTMLを生成します。次に、生成したHTMLをcustomCalendar要素に挿入します。最後に、カレンダーの各要素(前月/次月ボタン、日付)にイベントリスナーを追加します。
カレンダーのヘッダー部分の作成
// カレンダーのヘッダー部分を作成
function createCalendarHeader(year, month) {
return `
<div class="calendar-header">
<button id="prev-month"><</button>
<span>${year}年${month + 1}月</span>
<button id="next-month">></button>
</div>
<div class="calendar-grid">
<div class="calendar-day-header">日</div>
<div class="calendar-day-header">月</div>
<div class="calendar-day-header">火</div>
<div class="calendar-day-header">水</div>
<div class="calendar-day-header">木</div>
<div class="calendar-day-header">金</div>
<div class="calendar-day-header">土</div>
`;
}
- カレンダーのヘッダー部分のHTMLを生成
- 年月の表示、前月/次月ボタン、曜日の表示を含む
この関数は、カレンダーのヘッダー部分のHTMLを生成します。ヘッダーには、現在の年月、前月と次月に移動するためのボタン、そして曜日の表示が含まれます。テンプレートリテラルを使用して、動的に年月を挿入しています。
カレンダーの日付部分の作成
// カレンダーの日付部分を作成
function createCalendarDays(firstDay, lastDay) {
let calendarHTML = '';
// 月の最初の日までの空白を追加
for (let i = 0; i < firstDay.getDay(); i++) {
calendarHTML += '<div></div>';
}
// 日付を追加
for (let i = 1; i <= lastDay.getDate(); i++) {
calendarHTML += `<div class="calendar-day">${i}</div>`;
}
return calendarHTML + '</div>';
}
- 月の最初の日までの空白を追加
- 1日から月末までの日付を追加
- 生成したHTMLを返す
この関数は、カレンダーの日付部分のHTMLを生成します。まず、月の最初の日が週の何日目かに応じて空白のdivを追加します。次に、1日から月末までの日付を表示するdivを追加します。これにより、カレンダーグリッド内で日付が正しい位置に表示されます。
カレンダーのイベントリスナーの追加
// カレンダーのイベントリスナーを追加
function addCalendarEventListeners(year, month) {
// 前月ボタン
document.getElementById('prev-month').addEventListener('click', (e) => {
e.stopPropagation();
currentCalendarDate = new Date(year, month - 1, 1);
renderCalendar(currentCalendarDate);
});
// 次月ボタン
document.getElementById('next-month').addEventListener('click', (e) => {
e.stopPropagation();
currentCalendarDate = new Date(year, month + 1, 1);
renderCalendar(currentCalendarDate);
});
// 各日付にクリックイベントを追加
customCalendar.querySelectorAll('.calendar-day').forEach(day => {
day.addEventListener('click', () => {
selectedDate = new Date(year, month, parseInt(day.textContent));
updateDateDisplay(selectedDate);
hideCalendar();
});
});
}
- 前月/次月ボタンにクリックイベントリスナーを追加
- 各日付にクリックイベントリスナーを追加
- 日付クリック時に選択日を更新し、カレンダーを非表示に
この関数は、カレンダーの各要素にイベントリスナーを追加します。前月と次月のボタンには、クリック時に適切な月のカレンダーを表示するイベントリスナーを設定します。各日付には、クリック時に選択された日付を更新し、カレンダーを非表示にするイベントリスナーを設定します。これにより、ユーザーがカレンダー上で日付を選択できるようになります。
カレンダー外クリック時の処理
// カレンダー外をクリックした時の処理
function handleOutsideClick(e) {
if (!customCalendar.contains(e.target) && e.target !== dateSelectBtn) {
hideCalendar();
}
}
- クリックされた要素がカレンダーの外部かどうかを確認
- カレンダー外のクリックでカレンダーを非表示に
この関数は、ドキュメント全体に対するクリックイベントを処理します。クリックされた要素がカレンダーの外部で、かつ日付選択ボタンでもない場合、カレンダーを非表示にします。これにより、ユーザーがカレンダー外をクリックした際に自動的にカレンダーが閉じるようになります。
選択された日付の表示更新
// 選択された日付の表示を更新
function updateDateDisplay(date) {
const days = ['日', '月', '火', '水', '木', '金', '土'];
selectedDateSpan.textContent = `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日(${days[date.getDay()]})`;
}
- 選択された日付を指定のフォーマットで表示
- 年月日と曜日を含む
この関数は、ユーザーが選択した日付を適切なフォーマットで表示します。日本語の曜日表示を含め、「YYYY年MM月DD日(曜日)」の形式で日付を表示します。これにより、ユーザーが選択した日付を明確に確認できます。
エラー処理と表示
// エラーメッセージをリセット
function resetErrors() {
taskError.textContent = '';
dateError.textContent = '';
}
// エラーメッセージを表示
function showError(element, message) {
element.textContent = message;
}
- resetErrors: エラーメッセージをクリア
- showError: 指定された要素にエラーメッセージを表示
これらの関数は、フォームのバリデーションエラーを処理します。resetErrorsは、すべてのエラーメッセージをクリアします。showErrorは、指定された要素に特定のエラーメッセージを表示します。これらを使用することで、ユーザーに適切なフィードバックを提供し、フォームの正しい入力を促します。
フォームのリセット
// フォームをリセット
function resetForm() {
taskInput.value = '';
selectedDate = '';
selectedDateSpan.textContent = '';
}
- タスク入力フィールドをクリア
- 選択された日付をリセット
- 日付表示をクリア
この関数は、タスクが正常に追加された後やユーザーがフォームをリセットしたい場合に呼び出されます。タスク入力フィールドをクリアし、選択された日付をリセットします。また、画面上の日付表示もクリアします。これにより、ユーザーは新しいタスクを入力する準備が整います。
初期表示時のタスク表示
// 初期表示時にタスクを表示
uiManager.renderTasks();
- アプリケーション起動時に既存のタスクを表示
このコードは、DOMContentLoadedイベントリスナーの最後に配置されています。アプリケーションが起動し、DOMの読み込みが完了した直後に実行されます。UIManagerのrenderTasksメソッドを呼び出すことで、既存のタスク(例えば、ローカルストレージに保存されているタスク)を画面に表示します。これにより、ユーザーは前回のセッションで追加したタスクを即座に確認できます。
このスクリプト全体は、即時実行関数(IIFE: Immediately Invoked Function Expression)の中に配置されているわけではありませんが、DOMContentLoadedイベントリスナーの中に全ての処理が含まれています。これには以下のような利点があります:
- グローバルスコープの汚染を防ぐ: 変数や関数がグローバルスコープに漏れるのを防ぎます。
- DOMの準備完了を保証: スクリプトがDOMの読み込み完了後に実行されることを保証し、DOM操作に関するエラーを防ぎます。
- モジュール的なアプローチ: コードを論理的なユニットにまとめることで、保守性と可読性が向上します。
まとめ
コードの特徴
- モジュール化されたアーキテクチャ(TaskManagerとUIManagerの分離)
- イベント駆動型のプログラミングスタイル
- カスタムカレンダーの動的生成と操作
- クロージャを利用した変数のスコープ管理
- **ES6+**の機能(アロー関数、テンプレートリテラル)の活用
- バリデーションとエラーハンドリングの実装
- DOM操作を効率的に行うための要素キャッシング
- 日付操作のための独自ロジック
このJavaScriptコードは、モダンで機能的なToDoリストアプリケーションのコアロジックを実装しています。コードは明確に構造化され、責任の分離原則に従ってTaskManagerとUIManagerクラスを利用しています。これにより、ビジネスロジックとユーザーインターフェース管理が適切に分離され、コードの保守性と拡張性が向上しています。
アプリケーションの主要機能として、タスクの追加、日付の選択、カスタムカレンダーの表示と操作が実装されています。特に、カスタムカレンダーの実装は注目に値し、動的なHTML生成とイベントハンドリングを組み合わせて、ユーザーフレンドリーな日付選択インターフェースを提供しています。
コード全体を通して、モダンなJavaScript機能が効果的に活用されています。アロー関数やテンプレートリテラルの使用は、コードの簡潔さと可読性を向上させています。また、イベントリスナーの適切な使用とイベントの伝播制御により、ユーザーインタラクションを効果的に管理しています。
バリデーションとエラーハンドリングも適切に実装されており、ユーザー入力の検証とフィードバックの提供を確実に行っています。これにより、アプリケーションの堅牢性と使いやすさが向上しています。
コメント