iT邦幫忙

2025 iThome 鐵人賽

DAY 11
0
Modern Web

Modern Web × AI《拖延怪日記》:語錄陪伴擺脫拖延系列 第 11

【Day 11】- 入門 JavaScript 網頁架設:篩選

  • 分享至 

  • xImage
  •  

摘要
Day 10 我們能依照時間、任務或原因來排序清單。
今天要進一步加入「篩選」功能(只顯示特定原因的紀錄),並補上排序與篩選的「多分頁同步」,讓不同分頁的排序/篩選偏好保持一致。

為什麼要篩選?

  • 篩選:只想看「太累」或「沒心情」的紀錄。
  • 程式學習:練習 array.filter() 與 window.storage。

核心概念

  1. 篩選:在 applySortFilter() 先過濾,再交給 Day 10 的排序。
  2. 同步:監聽 window.storage,在其他分頁變動時自動更新 UI。
  3. 組合邏輯:篩選後仍然能依照 Day 10 的排序規則排列。

實作步驟

HTML:

<label for="filterSelect">篩選:</label>
<select id="filterSelect">
  <option value="all">全部</option>
  <option value="tired">只看「太累」</option>
  <option value="mood">只看「沒心情」</option>
  <option value="distractions">只看「太多干擾」</option>
  <option value="difficult">只看「太難」</option>
  <option value="dontKnow">只看「不知道怎麼開始」</option>
  <option value="other">只看「其他」</option>
</select>

JavaScript:

// ===== 常數與兼容處理 =====
const FILTER_PREF_KEY = 'procrastinator_filter_pref';
let currentFilter = localStorage.getItem(FILTER_PREF_KEY) || 'all';

// ===== 狀態 =====
const filterSelect = document.getElementById('filterSelect');

// 篩選+排序
function applySortFilter(list) {
  let arr = Array.isArray(list) ? list.slice() : [];

  // 篩選
  const f = (filterSelect?.value ?? currentFilter);
  if (f && f !== 'all') {
    arr = arr.filter(r => r.reasonCode === f); // reasonCode(例如 "tired", "mood"),表示下拉清單上的拖延原因
  }

  // 排序(沿用 Day 10 的 applySort)
  const s = (sortSelect?.value ?? currentSort);
  switch (s) {
    case 'time_asc':
      arr.sort((a, b) => a.createdAt - b.createdAt);
      break;
    case 'reason':
      arr.sort((a, b) => (a.reason || '').localeCompare(b.reason || ''));
      break;
    case 'task':
      arr.sort((a, b) => (a.task || '').localeCompare(b.task || ''));
      break;
    case 'time_desc':
    default:
      arr.sort((a, b) => b.createdAt - a.createdAt);
      break;
  }
  return arr;
}

// ===== 渲染(新到舊),每筆帶 data-id (改動一列)=====
function renderHistory() {
  const el = document.getElementById('historyList');
  // 改用 applySortFilter 套用目前排序/篩選,原為 const records = readRecords().slice().sort((a,b) => b.createdAt - a.createdAt);
  const records = applySortFilter(readRecords());

  el.innerHTML = records.length
    ? records.map(r => `
        <li>
          [${new Date(r.createdAt).toLocaleString()}] ${r.task} — ${r.reason} |「${r.quote}」
          <button class="btn-delete" data-id="${r.id}">刪除</button>
        </li>
      `).join('')
    : '<li class="muted">尚無紀錄</li>';

  // stack 有東西才啟用回復按鈕
  undoBtn.disabled = deletedStack.length === 0;
}

// 篩選下拉事件
filterSelect?.addEventListener('change', (e) => {
  currentFilter = e.target.value;
  localStorage.setItem(FILTER_PREF_KEY, currentFilter);
  renderHistory();
});

// 多分頁同步
window.addEventListener('storage', (e) => {
  if (e.key === SORT_PREF_KEY) {
    currentSort = localStorage.getItem(SORT_PREF_KEY) || 'time_desc';
    if (sortSelect) sortSelect.value = currentSort;
    renderHistory();
  }
  if (e.key === FILTER_PREF_KEY) {
    currentFilter = localStorage.getItem(FILTER_PREF_KEY) || 'all';
    if (filterSelect) filterSelect.value = currentFilter;
    renderHistory();
  }
});

// ===== 初次載入 =====
(function initFilterUI() {
  if (filterSelect) filterSelect.value = currentFilter;
})();

驗證

  • 篩選:新增不同原因的紀錄,切換選單應只顯示對應項目。
  • 與排序結合:先篩選「太累」,再切換排序,結果應同時生效。
  • 偏好記住:切到「依原因」+「只看太累」,重新整理後應維持設定。
  • 多分頁同步:在分頁 A 切換篩選,分頁 B 應自動同步。

上一篇
【Day 10】- 入門 JavaScript 網頁架設:排序
下一篇
【Day 12】入門 JavaScript 網頁架設:進場畫面
系列文
Modern Web × AI《拖延怪日記》:語錄陪伴擺脫拖延19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言