完成了狀態管理與 Modal 互動視窗後,接下來的目標是將任務清單(Accordion 摺疊區塊)動態化,讓主任務與子任務的新增、修改、刪除(CRUD)能即時反映在畫面上。
在實作動態渲染之前,需要先調整 HTML 結構。
將原本在 HTML 寫死的 Accordion 內文全部刪除,僅保留最外層的容器。這是因為當資料交由 JavaScript 的 tasks 陣列管理後,畫面上的內容將完全由 JS 動態生成。如果保留寫死內容,不僅會造成重複,也會破壞資料與介面的同步。
<!-- 任務清單列表 (動態渲染容器) -->
<div class="accordion shadow-sm" id="task-accordionExample">
<!-- JavaScript 將會自動在這裡渲染主任務與子任務內容 -->
</div>
renderTaskAccordion()當 tasks 資料變動時,我們透過 DOM 操作來更新 Accordion。
主要的實作步驟如下:
空資料處理:當 tasks 為空陣列時,顯示「目前尚無任務」的友善提示畫面。
依序處理主任務(map):將每一個主任務渲染成一個 Accordion Item(折疊卡片)。
依序處理子任務:在主任務展開區塊內,走訪該任務下的 subtasks 陣列,渲染出子任務清單列表。
綁定操作按鈕:在子任務旁邊放上「編輯」與「刪除」按鈕,並直接綁定 updateSubtask() 與 deleteSubtask() 事件。
// 簡略示意:Accordion 動態渲染邏輯
function renderTaskAccordion() {
const accordionContainer = document.querySelector("#task-accordionExample");
if (!accordionContainer) return;
// 1. 無資料時的空狀態顯示
if (tasks.length === 0) {
accordionContainer.innerHTML = `<div class="text-center p-5 text-muted">目前尚無主任務</div>`;
return;
}
// 2. 組裝 HTML 結構
const accordionHTML = tasks.map((task, index) => {
const subtasksHTML = task.subtasks.map(sub => `
<li class="list-group-item d-flex justify-content-between align-items-center">
<span>${sub.title}</span>
<div>
<button class="btn btn-sm btn-outline-secondary" onclick="updateSubtask('${task.id}', '${sub.id}')">編輯</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteSubtask('${task.id}', '${sub.id}')">刪除</button>
</div>
</li>
`).join("");
return `
<div class="accordion-item">
<h2 class="accordion-header">${task.title}</h2>
<div class="accordion-collapse collapse ${index === 0 ? 'show' : ''}">
<ul class="list-group list-group-flush">${subtasksHTML}</ul>
</div>
</div>
`;
}).join("");
accordionContainer.innerHTML = accordionHTML;
}
為了確保所有元件(計時器下拉選單、Modal 選單、Accordion 清單)的資料保持一致,我們將所有渲染函式統一收攬至 renderAll() 中:
function renderAll() {
renderCurrentTaskDisplay();
renderManageMainTaskList();
renderMainTaskDropdown();
renderSubtaskDropdown();
renderModalParentDropdown();
renderTaskAccordion(); // 呼叫 Accordion 渲染
}
無論是新增子任務、修改主任務名稱,還是刪除項目,最後只需要呼叫 renderAll(),就能自動重新繪製最新畫面。
