先日の”今の段階では、「とりあえず動いていればOK」と考え、実際に動作するコードをどんどん活用していくのが良いアプローチです。by ChatGPT”というアドバイス通り、今日はどんどん進みます。新しいコードを見て、説明はもちろんできませんが何となく書いてあることは理解できます。あの地獄の4日間は無駄じゃなかったということです。ということで今日も張り切っていきましょう!
初めての人はお金持ちまでの道のり:0日目をまず読んでみてください!よろしくお願いします★
色・優先度&期限の選択・ボタン・内容の編集(Level 2)
最初の状態から変わったことは、色・優先度レベルの選択・期限の選択・ボタンの大きさ・断念ボタンを押したときの確認・目標の内容と期限を一画面で編集の6点です。一番めんどくさかったのが最後の「目標の内容と期限を一画面で編集」です。もともとは編集ボタンを押すと、目標の編集画面が出て、その編集が終わってから期限の編集画面が出てきます。ただそれを一緒にしたかっただけなのに。。。
ということで以下がToDoリストアプリ(Level 2)のスクショとそのコードです。
<!-- 編集用のモーダル -->
<div id="editModal" style="display: none;">
<div class="modal-content">
<h3>タスクを編集</h3>
<label for="edit-task">目標を編集:</label>
<input type="text" id="edit-task">
<br>
<label for="edit-deadline">期限を編集:</label>
<input type="date" id="edit-deadline">
<br><br>
<button onclick="saveEdit()">保存</button>
<button onclick="closeModal()">キャンセル</button>
</div>
</div>
<style>
/* モーダルのスタイル */
#editModal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px;
border: 1px solid #ccc;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
z-index: 1000;
}
.modal-content {
max-width: 400px;
margin: auto;
padding: 10px;
}
</style>
<div id="todo-app">
<input type="text" id="new-task" placeholder="年内の目標は?">
<select id="priority">
<option value="low">優先度レベル(低)</option>
<option value="medium">優先度レベル(中)</option>
<option value="high">優先度レベル(高)</option>
</select>
<input type="date" id="deadline"> <!-- 期限を入力するフィールド -->
<button id="click-btn" onclick="addTask()">クリック</button>
<ul id="task-list"></ul>
</div>
<style>
button {
margin-right: 10px; /* ボタン間の余白を10pxに設定 */
}
/* 年内の目標を書く欄の背景色を赤に設定 */
#new-task {
background-color: yellow;
}
#click-btn {
font-size: 20px;
padding: 10px 20px;
background-color: orange; /* 背景色を緑に設定 */
color: white; /* テキストの色を白に設定(見やすくするため) */
}
</style>
<script>
let tasks = [];
// ページ読み込み時にローカルストレージからタスクを取得して表示
window.onload = function() {
let savedTasks = JSON.parse(localStorage.getItem('taskList')) || [];
tasks = savedTasks;
renderTasks();
};
function addTask() {
let taskText = document.getElementById('new-task').value;
let taskPriority = document.getElementById('priority').value; // 優先度を取得
let taskDeadline = document.getElementById('deadline').value; // 期限を取得
if (taskText !== "") {
tasks.push({ text: taskText, completed: false, priority: taskPriority, deadline: taskDeadline });
localStorage.setItem('taskList', JSON.stringify(tasks)); // ローカルストレージに保存
document.getElementById('new-task').value = "";
document.getElementById('deadline').value = ""; // 期限フィールドをクリア
renderTasks();
}
}
function renderTasks() {
let taskList = document.getElementById('task-list');
taskList.innerHTML = ""; // 一旦リストをクリア
tasks.forEach((task, index) => {
let listItem = document.createElement('li');
// タスクのテキスト部分を <span> タグで包む
let taskText = document.createElement('span');
taskText.textContent = `${task.text} (期限: ${task.deadline})`; // 期限を表示
// タスクのテキストとボタンの間に余白を追加
taskText.style.marginRight = "20px";
// タスクのテキストをリストアイテムに追加
listItem.appendChild(taskText);
// 優先度に応じて色を変える
if (task.priority === "high") {
listItem.style.color = "red";
} else if (task.priority === "medium") {
listItem.style.color = "orange";
} else {
listItem.style.color = "green";
}
// タスクが完了したら取り消し線を表示
if (task.completed) {
listItem.style.textDecoration = "line-through";
}
// タスク完了ボタン
let completeButton = document.createElement('button');
completeButton.textContent = "達成!";
completeButton.onclick = () => {
completeTask(index);
};
// タスク削除ボタン
let deleteButton = document.createElement('button');
deleteButton.textContent = "断念。。";
deleteButton.onclick = () => {
deleteTask(index);
};
// タスク編集ボタン
let editButton = document.createElement('button');
editButton.textContent = "編集★";
editButton.onclick = () => {
editTask(index);
};
// ボタンをリストに追加
listItem.appendChild(completeButton);
listItem.appendChild(deleteButton);
listItem.appendChild(editButton);
// タスクをリストに追加
taskList.appendChild(listItem);
});
}
function completeTask(index) {
tasks[index].completed = !tasks[index].completed; // 完了/未完了を切り替え
localStorage.setItem('taskList', JSON.stringify(tasks)); // 状態を保存
renderTasks(); // リストを再描画
}
function deleteTask(index) {
// 確認メッセージを表示
let confirmation = confirm("本当に?");
// OKを押した場合のみ削除を実行
if (confirmation) {
tasks.splice(index, 1); // タスクを削除
localStorage.setItem('taskList', JSON.stringify(tasks)); // 状態を保存
renderTasks(); // リストを再描画
}
}
let currentTaskIndex = null; // 編集中のタスクのインデックス
function editTask(index) {
// モーダルを表示する前に、既存の目標と期限をフォームに設定
document.getElementById('edit-task').value = tasks[index].text;
document.getElementById('edit-deadline').value = tasks[index].deadline;
currentTaskIndex = index; // 現在編集中のタスクのインデックスを保存
document.getElementById('editModal').style.display = 'block'; // モーダルを表示
}
function saveEdit() {
// フォームから新しい目標と期限を取得
let newTask = document.getElementById('edit-task').value;
let newDeadline = document.getElementById('edit-deadline').value;
// タスクを更新
if (newTask !== "" && newDeadline !== "") {
tasks[currentTaskIndex].text = newTask;
tasks[currentTaskIndex].deadline = newDeadline;
localStorage.setItem('taskList', JSON.stringify(tasks)); // 状態を保存
renderTasks(); // リストを再描画
closeModal(); // モーダルを閉じる
}
}
function closeModal() {
document.getElementById('editModal').style.display = 'none'; // モーダルを非表示
}
</script>
なんか見た目が非常にダサいです。ということでかっこよく改良していきます。
文字をゲームっぽくする(Level 3)
ゲームっぽい文字にしてみました。日本語にしたかったのですが、何度やっても日本語でゲームっぽい文字が表示できませんでした。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToDoリストアプリ</title>
<!-- Google Fontsなどの追加が必要であればここにリンクを貼り付け -->
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet"> /* 英数字にドラクエ風のピクセルフォントを適用するためのフォント */
<!-- CSSをここに記述 -->
<style>
/* ドラクエ風のスタイルを #todo-app に限定 */
#todo-app {
font-family: 'Press Start 2P', cursive;
background-color: #2c2c54;
color: #ffffff;
padding: 20px;
border: 2px solid #ffffff;
width: 60%;
margin: auto;
}
#todo-app input, #todo-app select, #todo-app button {
font-family: 'Press Start 2P', cursive;
border: 2px solid #ffffff;
background-color: #2c2c54;
color: #ffffff;
padding: 10px;
margin: 5px 0;
}
#todo-app #click-btn {
font-size: 20px;
padding: 10px 20px;
background-color: #f39c12;
color: white;
border: 2px solid #ffffff;
}
#todo-app ul {
list-style-type: none;
padding: 0;
}
#todo-app li {
padding: 10px;
margin-bottom: 5px;
background-color: #2c2c54;
border: 2px solid #ffffff;
}
#todo-app button {
border: 2px solid #ffffff;
background-color: #e74c3c;
color: #ffffff;
}
h2, h3 {
color: #ffffff;
}
/* モーダルのスタイル */
#editModal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px;
border: 1px solid #ccc;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
z-index: 1000;
}
.modal-content {
max-width: 400px;
margin: auto;
padding: 10px;
}
</style>
</head>
<body>
<!-- ToDoリストのHTML部分 -->
<div id="todo-app">
<input type="text" id="new-task" placeholder="年内の目標は?">
<select id="priority">
<option value="low">Level(Low)[white]</option>
<option value="medium">Level(Normal)[orange]</option>
<option value="high">Level(High)[red]</option>
</select>
<input type="date" id="deadline"> <!-- 期限を入力するフィールド -->
<button id="click-btn" onclick="addTask()">Click</button>
<ul id="task-list"></ul>
</div>
<!-- 編集用のモーダル -->
<div id="editModal" style="display: none;">
<div class="modal-content">
<h3>Edit</h3>
<label for="edit-task">Edit the task:</label>
<input type="text" id="edit-task">
<br>
<label for="edit-deadline">Edit the deadline:</label>
<input type="date" id="edit-deadline">
<br><br>
<button onclick="saveEdit()">Save</button>
<button onclick="closeModal()">Cancel</button>
</div>
</div>
<!-- JavaScriptコード -->
<script>
let tasks = [];
// ページ読み込み時にローカルストレージからタスクを取得して表示
window.onload = function() {
let savedTasks = JSON.parse(localStorage.getItem('taskList')) || [];
tasks = savedTasks;
renderTasks();
};
function addTask() {
let taskText = document.getElementById('new-task').value;
let taskPriority = document.getElementById('priority').value; // 優先度を取得
let taskDeadline = document.getElementById('deadline').value; // 期限を取得
if (taskText !== "") {
tasks.push({ text: taskText, completed: false, priority: taskPriority, deadline: taskDeadline });
localStorage.setItem('taskList', JSON.stringify(tasks)); // ローカルストレージに保存
document.getElementById('new-task').value = "";
document.getElementById('deadline').value = ""; // 期限フィールドをクリア
renderTasks();
}
}
function renderTasks() {
let taskList = document.getElementById('task-list');
taskList.innerHTML = ""; // 一旦リストをクリア
tasks.forEach((task, index) => {
let listItem = document.createElement('li');
// タスクのテキスト部分を <span> タグで包む
let taskText = document.createElement('span');
taskText.textContent = `${task.text} (Deadline: ${task.deadline})`; // 期限を表示
// タスクのテキストとボタンの間に余白を追加
taskText.style.marginRight = "20px";
// タスクのテキストをリストアイテムに追加
listItem.appendChild(taskText);
// ボタンを縦に配置するために改行を追加
listItem.appendChild(document.createElement('br')); // 改行を追加
// 優先度に応じて色を変える
if (task.priority === "high") {
listItem.style.color = "#FF6347";
} else if (task.priority === "medium") {
listItem.style.color = "orange";
} else {
listItem.style.color = "white";
}
// タスクが完了したら取り消し線を表示
if (task.completed) {
listItem.style.textDecoration = "line-through";
}
// タスク完了ボタン
let completeButton = document.createElement('button');
completeButton.textContent = "Done!";
completeButton.onclick = () => {
completeTask(index);
};
// タスク削除ボタン
let deleteButton = document.createElement('button');
deleteButton.textContent = "Give up";
deleteButton.onclick = () => {
deleteTask(index);
};
// タスク編集ボタン
let editButton = document.createElement('button');
editButton.textContent = "Edit";
editButton.onclick = () => {
editTask(index);
};
// ボタンをリストに追加
listItem.appendChild(completeButton);
listItem.appendChild(deleteButton);
listItem.appendChild(editButton);
// タスクをリストに追加
taskList.appendChild(listItem);
});
}
function completeTask(index) {
tasks[index].completed = !tasks[index].completed; // 完了/未完了を切り替え
localStorage.setItem('taskList', JSON.stringify(tasks)); // 状態を保存
renderTasks(); // リストを再描画
}
function deleteTask(index) {
// 確認メッセージを表示
let confirmation = confirm("本当に?");
// OKを押した場合のみ削除を実行
if (confirmation) {
tasks.splice(index, 1); // タスクを削除
localStorage.setItem('taskList', JSON.stringify(tasks)); // 状態を保存
renderTasks(); // リストを再描画
}
}
let currentTaskIndex = null; // 編集中のタスクのインデックス
function editTask(index) {
// モーダルを表示する前に、既存の目標と期限をフォームに設定
document.getElementById('edit-task').value = tasks[index].text;
document.getElementById('edit-deadline').value = tasks[index].deadline;
currentTaskIndex = index; // 現在編集中のタスクのインデックスを保存
document.getElementById('editModal').style.display = 'block'; // モーダルを表示
}
function saveEdit() {
// フォームから新しい目標と期限を取得
let newTask = document.getElementById('edit-task').value;
let newDeadline = document.getElementById('edit-deadline').value;
// タスクを更新
if (newTask !== "" && newDeadline !== "") {
tasks[currentTaskIndex].text = newTask;
tasks[currentTaskIndex].deadline = newDeadline;
localStorage.setItem('taskList', JSON.stringify(tasks)); // 状態を保存
renderTasks(); // リストを再描画
closeModal(); // モーダルを閉じる
}
}
function closeModal() {
document.getElementById('editModal').style.display = 'none'; // モーダルを非表示
}
</script>
</body>
</html>
リマインドを付ける(Level 4)
functionの関数は順番が自由なので、functionが並んでいるところあたりにコピペするだけです。
// タスクの期限が近づいているか確認してリマインダーを表示する
function checkReminders() {
let today = new Date();
tasks.forEach(task => {
if (task.deadline) {
let deadline = new Date(task.deadline);
let timeDiff = deadline - today;
// 期限が1週間以内の場合にリマインド
if (timeDiff > 0 && timeDiff <= 7 * 24 * 60 * 60 * 1000) {
alert(`「${task.text}」の期限が近づいています!(期限: ${task.deadline})`);
}
}
});
}
パソコンを開く度にリマインドされるのではなく、このHPを訪れた時にリマインドされます。ここの常連でないと全く意味のない機能です。。
・一日前
if (timeDiff > 0 && timeDiff <= 24 * 60 * 60 * 1000)
・一週間前
if (timeDiff > 0 && timeDiff <= 7 * 24 * 60 * 60 * 1000)
・一カ月前(30日目)
if (timeDiff > 0 && timeDiff <= 30 * 24 * 60 * 60 * 1000)
・一年前(365日前)
if (timeDiff > 0 && timeDiff <= 365 * 24 * 60 * 60 * 1000)
JavaScriptでは関数の順番は比較的自由に決めることができます。特に 関数宣言(function
で定義されたもの)は ホイスティング(hoisting)という仕組みにより、スクリプト内のどこに書かれていても使用することができます。つまり、関数を呼び出すコードが関数の定義より前にあっても、正常に動作します。
端末に合わせたレスポンシブデザイン(Level 5)
デフォルトのレスポンシブデザイン(PCや大きな画面向け)の下にコピペするだけです。これで端末に合わせてデザインが変更され、ユーザーフレンドリーなサイトになります。
/* スマートフォン向けのレスポンシブデザイン */
@media (max-width: 768px) {
#todo-app {
width: 90%; /* 画面幅を90%に変更 */
padding: 10px;
margin: 10px auto; /* モバイルで中央揃え */
}
#todo-app input, #todo-app select, #todo-app button {
padding: 8px;
font-size: 16px; /* テキストサイズを調整 */
}
#todo-app #click-btn {
font-size: 18px;
padding: 8px 15px;
}
#todo-app ul li {
padding: 8px;
font-size: 16px; /* リスト項目も小さくする */
}
#todo-app button {
padding: 8px;
font-size: 14px;
}
/* ボタンがスマートフォンで重ならないように */
#todo-app li button {
display: block;
width: 100%; /* ボタンを画面幅いっぱいに広げる */
margin: 5px 0;
}
}
/* タブレット向けのレスポンシブデザイン */
@media (max-width: 1024px) {
#todo-app {
width: 80%; /* 画面幅を80%に変更 */
}
#todo-app input, #todo-app select, #todo-app button {
font-size: 18px; /* テキストサイズを少し小さく */
}
#todo-app #click-btn {
font-size: 18px;
padding: 10px 15px;
}
#todo-app ul li {
font-size: 18px;
}
}
この設定はこのアプリ限定ではなくHP全体に設定すべきコードなので、アプリ内のコードには載せず、HPの追加CSSにコピペしました。
ボタンのホバーエフェクト(Level 6)
二つのグループのボタンにホバーエフェクトをかけようと思ったら失敗しました。以下のようにifっぽく設定するみたいです。
/* 特定のボタンへのホバーエフェクト */
#todo-app button:hover {
background-color: #ff6f61; /* ホバー時に明るくする */
color: #000000; /* テキストの色を変更 */
}
/* その他のボタンへのホバーエフェクト */
#click-btn:hover:not(#todo-app) {
background-color: #ff6f61; /* ホバー時に明るくする */
color: #000000; /* テキストの色を変更 */
}
#click-btn内に"Click"ボタンがあり、#todo-app
内に"Done!","Give up","Edit"ボタンがある。上記のコードのようにifっぽく別々に設定したらうまくいった。
ChatGPT曰く、何かと競合している可能性が高いとのこと。本来はnotを使う必要はないらしい。恐らくHPのヘッダーのボタンを避けてコードを書いたから、それでこんなことになっているのではと予想している。これが先日ChatGPTが言っていた「とりあえず動けば良い」の好例だと思う。
CSSコードの記入順は基本的に自由。スタイルの競合が発生する場合があるので、優先順位(Specificity) によってどのスタイルが適用されるかを気にする必要がある。
優先順位(Specificity)
1.インラインスタイル(HTMLタグ内に直接書かれたスタイル):
2.IDセレクタ: #id
3.クラスセレクタ、属性セレクタ、擬似クラスセレクタ: .class, input[type="text"], :hover
4.タグセレクタ(要素セレクタ): div, p, button
5.すべての要素セレクタ(ユニバーサルセレクタ): *
※もし同じ要素に対して複数のスタイルが適用される場合、後から書かれたスタイルが優先される
視覚的にわかりやすいアイコンの使用
Font Awesome(アイコンライブラリ)
HTMLの<head>
内にFont Awesome(アイコンライブラリ)のリンクを追加します。
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
ボタンにアイコンを追加
変更前
<button id="click-btn" onclick="addTask()">Click</button>
変更後(アイコンを使用)
<button id="click-btn" onclick="addTask()"><i class="fas fa-plus"></i> 追加</button>
変更前と変更後のコードをChatGPTに書いてもらうと、コードの訂正は楽だし、何がどう変わったかも視覚的にすぐ確認でき、作業がかなり捗るのでオススメです。
ダークモード対応
ダークモードとは、ユーザーインターフェースの配色を暗い色に変更する設定モードのことです。通常、明るい背景(白や薄い色)に黒や濃い色のテキストを表示するライトモード(通常モード)と対比され、ダークモードでは暗い背景(黒や濃い灰色など)に明るい色のテキストが表示されます。ダークモードは、視覚的な疲れを軽減し、特に低照度の環境で画面を見る際に目に優しいと言われています。
/* ダークモード対応 */
@media (prefers-color-scheme: dark) {
body {
background-color: #121212;
color: #ffffff;
}
#todo-app {
background-color: #1e1e1e;
border-color: #333333;
}
#todo-app input, #todo-app select, #todo-app button {
background-color: #333333;
border-color: #555555;
color: #ffffff;
}
#todo-app ul {
background-color: #1e1e1e;
}
#todo-app li {
background-color: #2c2c2c;
border-color: #555555;
}
#todo-app button:hover {
background-color: #ff6f61;
color: #000000;
}
input[type="text"], input[type="date"], select:hover {
background-color: #4b4b89;
border-color: #ff6f61;
}
}
この設定もこのアプリ限定ではなくHP全体に設定すべきコードなので、アプリ内のコードには載せず、HPの追加CSSにコピペしました。
ちなみに最終的に出来上がったのが以下のコードです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToDoリストアプリ</title>
<!-- Google Fontsなどの追加が必要であればここにリンクを貼り付け -->
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<!-- CSSをここに記述 -->
<style>
/* bodyのスタイルは削除する */
/* ドラクエ風のスタイルを #todo-app に限定 */
#todo-app {
font-family: 'Press Start 2P', cursive;
background-color: #2c2c54;
color: #ffffff;
padding: 20px;
border: 2px solid #ffffff;
width: 60%;
margin: auto;
}
#todo-app input, #todo-app select, #todo-app button {
font-family: 'Press Start 2P', cursive;
border: 2px solid #ffffff;
background-color: #2c2c54;
color: #ffffff;
padding: 10px;
margin: 5px 0;
}
#todo-app #click-btn {
font-size: 20px;
padding: 10px 20px;
background-color: #f39c12;
color: white;
border: 2px solid #ffffff;
}
#todo-app ul {
list-style-type: none;
padding: 0;
}
#todo-app li {
padding: 10px;
margin-bottom: 5px;
background-color: #2c2c54;
border: 2px solid #ffffff;
}
#todo-app button {
border: 2px solid #ffffff;
background-color: #e74c3c;
color: #ffffff;
}
h2, h3 {
color: #ffffff;
}
/* ボタンのデフォルトスタイル */
button {
background-color: #e74c3c; /* デフォルトの背景色 */
color: #ffffff; /* テキストの色 */
border: 2px solid #ffffff;
padding: 10px 20px;
cursor: pointer;
transition: background-color 0.3s ease, color 0.3s ease; /* なめらかな変化 */
}
/* 特定のボタンへのホバーエフェクト */
#todo-app button:hover {
background-color: #ff6f61; /* ホバー時に明るくする */
color: #000000; /* テキストの色を変更 */
}
#click-btn:hover:not(#todo-app) {
background-color: #ff6f61; /* ホバー時に明るくする */
color: #000000; /* テキストの色を変更 */
}
/* 入力フィールドのデフォルトスタイル */
input[type="text"], input[type="date"], select {
background-color: #2c2c54; /* デフォルトの背景色 */
color: #ffffff; /* テキストの色 */
border: 2px solid #ffffff;
padding: 10px;
margin: 5px 0;
transition: border-color 0.3s ease, background-color 0.3s ease;
}
/* 入力フィールドにホバーしたときのスタイル */
input[type="text"]:hover, input[type="date"]:hover, select:hover {
background-color: #4b4b89; /* 背景色を少し明るく */
border-color: #ff6f61; /* 枠線を変化させる */
}
/* モーダルのスタイル */
#editModal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px;
border: 1px solid #ccc;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
z-index: 1000;
}
.modal-content {
max-width: 400px;
margin: auto;
padding: 10px;
}
</style>
</head>
<body>
<!-- ToDoリストのHTML部分 -->
<div id="todo-app">
<input type="text" id="new-task" placeholder="年内の目標は?" style="background-color: white; color: black; border: 2px solid #ffffff;">
<select id="priority">
<option value="low">Level(Low)[white]</option>
<option value="medium">Level(Normal)[orange]</option>
<option value="high">Level(High)[red]</option>
</select>
<input type="date" id="deadline"> <!-- 期限を入力するフィールド -->
<button id="click-btn" onclick="addTask()">Click</button>
<ul id="task-list"></ul>
</div>
<!-- 編集用のモーダル -->
<div id="editModal" style="display: none;">
<div class="modal-content">
<h3>Edit</h3>
<label for="edit-task">Edit the task:</label>
<input type="text" id="edit-task">
<br>
<label for="edit-deadline">Edit the deadline:</label>
<input type="date" id="edit-deadline">
<br><br>
<button onclick="saveEdit()">Save</button>
<button onclick="closeModal()">Cancel</button>
</div>
</div>
<!-- JavaScriptコード -->
<script>
let tasks = [];
// ページ読み込み時にローカルストレージからタスクを取得して表示
window.onload = function() {
let savedTasks = JSON.parse(localStorage.getItem('taskList')) || [];
tasks = savedTasks;
renderTasks();
checkReminders(); // リマインダーのチェックを追加
};
function addTask() {
let taskText = document.getElementById('new-task').value;
let taskPriority = document.getElementById('priority').value; // 優先度を取得
let taskDeadline = document.getElementById('deadline').value; // 期限を取得
if (taskText !== "") {
tasks.push({ text: taskText, completed: false, priority: taskPriority, deadline: taskDeadline });
localStorage.setItem('taskList', JSON.stringify(tasks)); // ローカルストレージに保存
document.getElementById('new-task').value = "";
document.getElementById('deadline').value = ""; // 期限フィールドをクリア
renderTasks();
}
}
function renderTasks() {
let taskList = document.getElementById('task-list');
taskList.innerHTML = ""; // 一旦リストをクリア
tasks.forEach((task, index) => {
let listItem = document.createElement('li');
// タスクのテキスト部分を <span> タグで包む
let taskText = document.createElement('span');
taskText.textContent = `${task.text} (Deadline: ${task.deadline})`; // 期限を表示
// タスクのテキストとボタンの間に余白を追加
taskText.style.marginRight = "20px";
// タスクのテキストをリストアイテムに追加
listItem.appendChild(taskText);
// ボタンを縦に配置するために改行を追加
listItem.appendChild(document.createElement('br')); // 改行を追加
// 優先度に応じて色を変える
if (task.priority === "high") {
listItem.style.color = "#FF6347";
} else if (task.priority === "medium") {
listItem.style.color = "orange";
} else {
listItem.style.color = "white";
}
// タスクが完了したら取り消し線を表示
if (task.completed) {
listItem.style.textDecoration = "line-through";
}
// タスク完了ボタン
let completeButton = document.createElement('button');
completeButton.innerHTML = '<i class="fas fa-check"></i> Done!';
completeButton.onclick = () => {
completeTask(index);
};
// タスク削除ボタン
let deleteButton = document.createElement('button');
deleteButton.innerHTML = '<i class="fas fa-times"></i> Give up';
deleteButton.onclick = () => {
deleteTask(index);
};
// タスク編集ボタン
let editButton = document.createElement('button');
editButton.innerHTML = '<i class="fas fa-edit"></i> Edit';
editButton.onclick = () => {
editTask(index);
};
// ボタンをリストに追加
listItem.appendChild(completeButton);
listItem.appendChild(deleteButton);
listItem.appendChild(editButton);
// タスクをリストに追加
taskList.appendChild(listItem);
});
}
// タスクの期限が近づいているか確認してリマインダーを表示する
function checkReminders() {
let today = new Date();
tasks.forEach(task => {
if (task.deadline) {
let deadline = new Date(task.deadline);
let timeDiff = deadline - today;
// 期限が1週間以内の場合にリマインド
if (timeDiff > 0 && timeDiff <= 7 * 24 * 60 * 60 * 1000) {
alert(`「${task.text}」の期限が近づいています!(期限: ${task.deadline})`);
}
}
});
}
function completeTask(index) {
tasks[index].completed = !tasks[index].completed; // 完了/未完了を切り替え
localStorage.setItem('taskList', JSON.stringify(tasks)); // 状態を保存
renderTasks(); // リストを再描画
}
function deleteTask(index) {
// 確認メッセージを表示
let confirmation = confirm("本当に?");
// OKを押した場合のみ削除を実行
if (confirmation) {
tasks.splice(index, 1); // タスクを削除
localStorage.setItem('taskList', JSON.stringify(tasks)); // 状態を保存
renderTasks(); // リストを再描画
}
}
let currentTaskIndex = null; // 編集中のタスクのインデックス
function editTask(index) {
// モーダルを表示する前に、既存の目標と期限をフォームに設定
document.getElementById('edit-task').value = tasks[index].text;
document.getElementById('edit-deadline').value = tasks[index].deadline;
currentTaskIndex = index; // 現在編集中のタスクのインデックスを保存
document.getElementById('editModal').style.display = 'block'; // モーダルを表示
}
function saveEdit() {
// フォームから新しい目標と期限を取得
let newTask = document.getElementById('edit-task').value;
let newDeadline = document.getElementById('edit-deadline').value;
// タスクを更新
if (newTask !== "" && newDeadline !== "") {
tasks[currentTaskIndex].text = newTask;
tasks[currentTaskIndex].deadline = newDeadline;
localStorage.setItem('taskList', JSON.stringify(tasks)); // 状態を保存
renderTasks(); // リストを再描画
closeModal(); // モーダルを閉じる
}
}
function closeModal() {
document.getElementById('editModal').style.display = 'none'; // モーダルを非表示
}
</script>
</body>
</html>
本日の感想
今日はこれの他に、時間であいさつが変わるコードの改良もしました。ChatGPTのアドバイス通り、100%の理解を目指さずスピードを重視したつもりです。でもやっぱり最初からこれをやっていたら、コードの流れとかを全く理解できなかったと思うので、最初は時間をかけてコードを読み込んだ方がいいような気もします。
16日目の記事はこちら
ToDoリストアプリをHP上で使う方法 16日目 2024/10/22(お金持ちまでの道のり)
18-20日目の記事はこちら
フロントエンドフレームワーク 18-20日目 2024/10/24-26(お金持ちまでの道のり)
ここに初めて来た人はゼヒ0日目を読んでください。プログラミング知識0のおじさんがお金持ちになるまでのプランと熱い思いが載っています。私と一緒に運要素を排除したゴリゴリの脳筋プレイでお金持ちを目指しませんか?
0日目の記事はこちら
お金持ちまでの道のり:0日目
コードの読み方が全く分からないという方は以下の記事がオススメです。コードの読み方の説明が一番詳しく書かれてある記事です。
ToDoリストアプリの作成 12-15日目 2024/10/18-21(お金持ちまでの道のり)
コメント