w

API 參考

資料結構

Task 物件

interface Task {
  id: string; // 唯一識別碼
  text: string; // 任務描述
  completed: boolean; // 完成狀態
  dueDate?: string; // 可選截止日期(ISO 格式)
  priority: "low" | "medium" | "high"; // 優先級
  createdAt: Date; // 建立時間戳記
  completedAt?: Date; // 完成時間戳記(如已完成)
}

HistoryRecord 物件

interface HistoryRecord {
  id: string; // 唯一識別碼
  action: "created" | "completed" | "deleted" | "updated";
  description: string; // 人類可讀描述
  timestamp: Date; // 操作時間戳記
}

本機儲存 API

儲存鍵

  • 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") || "[]");

匯出/匯入 API

匯出格式

{
  "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 },
  }),
);

工具函式

ID 產生

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();
  });
}

瀏覽器相容性

所需 API

  • 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 整合

// 任務完成時傳送 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);
  }
}

下一步

查看使用範例了解實際應用場景,或瀏覽相關工具探索互補工具。

這個頁面對您有幫助嗎?