はじめに
"タイマー付きのToDoリスト"を作ってみました。
"従来のToDoリスト"では一度設定したタスクは消去しない限り残るのに対し、"タイマー付きのToDoリスト"では、タイムオーバーになったタスクは自動的に消えることが大きな特徴です。
基本仕様
- タスクそれぞれにタイマーを設定する(デフォルトは1h)
- タイムオーバーになると実施の有無にかかわらずタスクが自動的に消える
- ファイル保存、一括削除ができる(タスク保存したい場合はファイル保存を行う)
- タスクごとにチェック、削除ができる
- local storageにデータを保存している
想定される使用場面
- 難しいタスクを、細分化したタスクにして処理する
- 時々刻々発生する課題を新しいタスクとして記録する
- 1日の業務手順を、タイマー設定により計画・実行する
スクリプト
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo List</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<style>
input[type="number"] {
width: 60px;
margin-left: 10px;
}
.timer {
font-weight: bold;
color: red;
}
</style>
</head>
<body>
<div id="app">
<h1>Todo List</h1>
<textarea v-model="newTodos" placeholder="Enter multiple todos, each on a new line"></textarea>
<button @click="addTodos">Add Todos</button>
<button @click="saveToFile">Save to File</button>
<button @click="resetTodos">Reset</button>
<input type="number" v-model.number="defaultTime" placeholder="時間(時間単位)" min="0" />
<ul>
<li v-for="(todo, index) in todos" :key="index">
<input type="checkbox" v-model="todo.done" />
<span :style="{ textDecoration: todo.done ? 'line-through' : 'none' }">{{ todo.text }}</span>
<span class="timer" v-if="todo.remainingTime >= 0">{{ formatRemainingTime(todo.remainingTime) }}</span>
<button @click="removeTodo(index)">Remove</button>
</li>
</ul>
</div>
<script>
const app = Vue.createApp({
data() {
return {
newTodos: '',
todos: [],
defaultTime: 1 // 一定時間を保持する変数
};
},
mounted() {
const savedTodos = localStorage.getItem('todos');
if (savedTodos) {
this.todos = JSON.parse(savedTodos);
this.todos.forEach(todo => {
todo.remainingTime = this.calculateRemainingTime(todo.deleteAt);
});
}
this.startGlobalTimer();
},
watch: {
todos: {
deep: true,
handler(newTodos) {
localStorage.setItem('todos', JSON.stringify(newTodos));
}
}
},
methods: {
addTodos() {
const todosArray = this.newTodos.trim().split('\n').filter(todo => todo.trim() !== '');
todosArray.forEach(todoText => {
const deleteAt = Date.now() + this.defaultTime * 3600000;
this.todos.push({
text: todoText,
done: false,
deleteAt: deleteAt,
remainingTime: this.calculateRemainingTime(deleteAt)
});
});
this.newTodos = '';
},
removeTodo(index) {
this.todos.splice(index, 1);
},
saveToFile() {
const todosText = this.todos.map(todo => `${todo.text}${todo.done ? ' (done)' : ''}`).join('\n');
const blob = new Blob([todosText], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `todos-${timestamp}.txt`;
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
},
resetTodos() {
this.todos = [];
},
startGlobalTimer() {
setInterval(() => {
const now = Date.now();
this.todos = this.todos.filter(todo => {
todo.remainingTime = this.calculateRemainingTime(todo.deleteAt);
return todo.remainingTime > 0;
});
}, 1000);
},
calculateRemainingTime(deleteAt) {
const remainingTime = deleteAt - Date.now();
return remainingTime > 0 ? remainingTime : 0;
},
formatRemainingTime(remainingTime) {
const hours = Math.floor(remainingTime / 3600000);
const minutes = Math.floor((remainingTime % 3600000) / 60000);
const seconds = Math.floor((remainingTime % 60000) / 1000);
return `${hours}h ${minutes}m ${seconds}s `;
}
}
});
app.mount('#app');
</script>
</body>
</html>
技術的特徴
以下がアプリの主な技術的特徴です。
-
Vue.jsを使用したアプリケーション構成
- Vueの
data
とmethods
を活用して、タスクデータの管理やユーザー操作の処理を実装 - Vueの
mounted
ライフサイクルメソッドを利用し、ページの読み込み時にローカルストレージからタスクを読み込む処理が行われる
- Vueの
-
LocalStorageへの自動保存
-
watch
プロパティを使用し、todos
の変更を監視してリアルタイムでlocalStorageに保存する
-
-
タイマー機能
-
defaultTime
変数でタスクのデフォルトのタイムアウト時間(1時間)を設定 -
addTodos
メソッドでタスク追加時に「削除予定時刻」を設定し、remainingTime
を計算することで、残り時間が表示される -
startGlobalTimer
メソッドで1秒ごとに全タスクをチェックし、remainingTime
が0以下になったタスクはリストから自動削除される
-
-
タスクの残り時間を動的に表示
-
calculateRemainingTime
メソッドで各タスクの残り時間をミリ秒単位で計算し、formatRemainingTime
メソッドで「時:分:秒」にフォーマットする
-