API 參考
interface Task {
id: string; // 唯一識別碼
text: string; // 任務描述
completed: boolean; // 完成狀態
dueDate?: string; // 可選截止日期(ISO 格式)
priority: "low" | "medium" | "high"; // 優先級
createdAt: Date; // 建立時間戳記
completedAt?: Date; // 完成時間戳記(如已完成)
}
interface HistoryRecord {
id: string; // 唯一識別碼
action: "created" | "completed" | "deleted" | "updated";
description: string; // 人類可讀描述
timestamp: Date; // 操作時間戳記
}
todo-tasks:Task 物件陣列todo-history:HistoryRecord 物件陣列
// 儲存任務到本機儲存
localStorage.setItem("todo-tasks", JSON.stringify(tasks));
// 從本機儲存載入任務
const tasks = JSON.parse(localStorage.getItem("todo-tasks") || "[]");
// 儲存歷史到本機儲存
localStorage.setItem("todo-history", JSON.stringify(history));
// 從本機儲存載入歷史
const history = JSON.parse(localStorage.getItem("todo-history") || "[]");
{
"tasks": [
{
"id": "abc123",
"text": "Complete project",
"completed": false,
"dueDate": "2024-02-15",
"priority": "high",
"createdAt": "2024-02-01T10:00:00.000Z",
"completedAt": null
}
],
"exportDate": "2024-02-01T10:00:00.000Z"
}
function validateImportData(data) {
if (!data.tasks || !Array.isArray(data.tasks)) {
throw new Error("Invalid data format: tasks array required");
}
data.tasks.forEach((task) => {
if (!task.id || !task.text || typeof task.completed !== "boolean") {
throw new Error("Invalid task format");
}
});
return true;
}
// 任務建立
window.dispatchEvent(
new CustomEvent("taskCreated", {
detail: { task: newTask },
}),
);
// 任務完成
window.dispatchEvent(
new CustomEvent("taskCompleted", {
detail: { task: completedTask },
}),
);
// 任務更新
window.dispatchEvent(
new CustomEvent("taskUpdated", {
detail: { task: updatedTask },
}),
);
// 任務刪除
window.dispatchEvent(
new CustomEvent("taskDeleted", {
detail: { taskId: deletedTaskId },
}),
);
// 新增歷史記錄
window.dispatchEvent(
new CustomEvent("historyAdded", {
detail: { record: newRecord },
}),
);
function generateId() {
return Math.random().toString(36).substr(2, 9);
}
function getTomorrow() {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
return tomorrow.toISOString().split("T")[0];
}
function isOverdue(dueDate) {
return new Date(dueDate) < new Date();
}
function formatDate(date) {
return new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "short",
day: "numeric",
}).format(new Date(date));
}
function formatTimeAgo(date) {
const now = new Date();
const diff = now.getTime() - date.getTime();
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(diff / 3600000);
const days = Math.floor(diff / 86400000);
if (days > 0) return `${days} days ago`;
if (hours > 0) return `${hours} hours ago`;
if (minutes > 0) return `${minutes} minutes ago`;
return "Just now";
}
function sortTasks(tasks) {
return tasks.sort((a, b) => {
// 優先級排序
const priorityOrder = { high: 3, medium: 2, low: 1 };
const priorityDiff = priorityOrder[b.priority] - priorityOrder[a.priority];
if (priorityDiff !== 0) return priorityDiff;
// 截止日期排序
if (a.dueDate && b.dueDate) {
return new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime();
}
if (a.dueDate) return -1;
if (b.dueDate) return 1;
// 建立時間排序
return b.createdAt.getTime() - a.createdAt.getTime();
});
}
localStorage — 資料持久化JSON.parse/stringify — 資料序列化CustomEvent — 事件系統Intl.DateTimeFormat — 日期格式化
- Chrome 51+
- Firefox 50+
- Safari 10+
- Edge 12+
try {
const tasks = JSON.parse(localStorage.getItem("todo-tasks"));
} catch (error) {
console.error("Failed to load tasks:", error);
// 回退到空陣列
tasks = [];
}
function validateTask(task) {
const errors = [];
if (!task.text || task.text.trim().length === 0) {
errors.push("Task text is required");
}
if (!["low", "medium", "high"].includes(task.priority)) {
errors.push("Invalid priority level");
}
if (task.dueDate && isNaN(Date.parse(task.dueDate))) {
errors.push("Invalid due date format");
}
return errors;
}
// 大清單分頁
function getTasksPage(tasks, page = 1, pageSize = 50) {
const start = (page - 1) * pageSize;
const end = start + pageSize;
return tasks.slice(start, end);
}
// 虛擬捲動支援
function getVisibleTasks(tasks, scrollTop, viewportHeight, itemHeight) {
const startIndex = Math.floor(scrollTop / itemHeight);
const visibleCount = Math.ceil(viewportHeight / itemHeight);
return tasks.slice(startIndex, startIndex + visibleCount);
}
// 限制歷史記錄數量
function addHistoryRecord(history, record, maxRecords = 100) {
history.unshift(record);
if (history.length > maxRecords) {
history = history.slice(0, maxRecords);
}
return history;
}
// 清理舊已完成任務
function cleanupOldTasks(tasks, daysToKeep = 30) {
const cutoff = new Date();
cutoff.setDate(cutoff.getDate() - daysToKeep);
return tasks.filter((task) => !task.completed || task.completedAt > cutoff);
}
// 匯出到外部日曆
function exportToCalendar(tasks) {
const calendarEvents = tasks
.filter((task) => task.dueDate && !task.completed)
.map((task) => ({
title: task.text,
start: task.dueDate,
priority: task.priority,
}));
// 產生日曆檔案或傳送到 API
return calendarEvents;
}
// 從外部來源匯入
async function importFromExternal(source) {
try {
const response = await fetch(source);
const data = await response.json();
if (validateImportData(data)) {
return data.tasks;
}
} catch (error) {
console.error("Import failed:", error);
throw error;
}
}
// 任務完成時傳送 Webhook
async function sendWebhook(task, webhookUrl) {
try {
await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
event: "taskCompleted",
task: task,
timestamp: new Date().toISOString(),
}),
});
} catch (error) {
console.error("Webhook failed:", error);
}
}
查看使用範例了解實際應用場景,或瀏覽相關工具探索互補工具。