需求:HTML 表格顯示資料,點擊「Life」等表頭欄位可對該欄進行升序/降序切換排序。純前端實現關鍵在於:**將 tbody 所有 tr 轉為陣列 → 根據欄位索引與資料型別排序 → 重新 append 回 DOM**。
Name
Life
Date
Status
Alice 85 2023-01-15 Active
Bob 92 2022-11-03 Inactive
Charlie 78 2023-05-20 Active
David 85 2023-01-15 Pending
| 步驟 | 關鍵代碼 | 說明 |
|---|---|---|
| 事件綁定 | th.addEventListener('click', ...) | 直接綁定在 th,簡單可靠 |
| 狀態管理 | sortState[colIndex] = 'asc'/'desc' | 記錄每欄當前排序方向 |
| 型別支援 | data-type="number|date|string" | HTML 屬性聲明,避免自動推斷錯誤 |
| 數字排序 | parseFloat(a) - parseFloat(b) | 升序;降序取負 |
| 日期排序 | new Date(a) - new Date(b) | 利用時間戳比較,支援 ISO 8601 |
| 字串排序 | localeCompare(..., {numeric:true}) | 自然排序 (1, 2, 10 而非 1, 10, 2) |
| DOM 更新 | DocumentFragment + appendChild | 批次操作,單次重排,效能最佳 |
sortState 存陣列 [{col, dir}, ...],sort 回呼中依序比較。IntersectionObserver) + Web Worker 排序,避免主執行緒阻塞。?sort=col&dir=asc,後端 ORDER BY 回傳新 HTML/JSON。localStorage.setItem('tableSort', JSON.stringify(sortState)),重載頁面恢復。tbody.innerHTML 重建字串 → 丟失事件綁定、輸入框焦點、效能差。rows.sort 修改原陣列但未重新掛載 → 畫面不變。2023/1/1 vs 2023-01-01) → new Date 解析失敗。**強制後端輸出 ISO 8601 (YYYY-MM-DD)**。parseFloat 失效。**預處理 val.replace(/[^0-9.-]/g, '')**。前端表格排序核心模式:**th[data-type] 聲明型別 → Array.from(rows).sort(compareFn) → DocumentFragment 批次掛載**。原生 JS 50 行即可實現生產級功能,無需引入 DataTables 等重型庫,靈活且效能可控。