iT邦幫忙

2025 iThome 鐵人賽

0
自我挑戰組

給愛追劇的你:30天互動網站挑戰系列 第 20

Day 20:資料持久化加強(版本鍵 + 資料結構升級)

  • 分享至 

  • xImage
  •  

我們在前面已完成收藏與心得的 LocalStorage。今天加上版本化資料完整性:可避免未來結構變更導致讀取出錯,並保留欄位升級空間。

改哪裡js/app.js(收藏)、js/reviews.js(心得)

1. 收藏:升級資料格式(加入時間戳)

把 Day10 中單純儲存 id 陣列 → 儲存物件陣列 { id, savedAt },並用版本鍵控制。

// js/app.js 收藏段落改寫
const FAV_KEY = 'dramaweb:fav:v2'; // v2 版本
function loadFavSet(){
  try{
    const raw = JSON.parse(localStorage.getItem(FAV_KEY) || '[]');
    // 支援舊版(v1:純 id 陣列)
    if (Array.isArray(raw) && raw.length && typeof raw[0] === 'string'){
      return new Map(raw.map(id => [id, {id, savedAt: Date.now()}]));
    }
    // v2:[{id,savedAt}]
    const map = new Map();
    (raw||[]).forEach(o => { if (o && o.id) map.set(o.id, {id:o.id, savedAt:o.savedAt || Date.now()}); });
    return map;
  }catch(e){ return new Map(); }
}
function saveFavMap(map){
  localStorage.setItem(FAV_KEY, JSON.stringify([...map.values()]));
}
let favMap = loadFavSet();
function isFav(id){ return favMap.has(id); }
function toggleFav(id){
  if (favMap.has(id)) favMap.delete(id);
  else favMap.set(id, { id, savedAt: Date.now() });
  saveFavMap(favMap);
}

favorites.js 讀取時也要相容 v2(把 Set 改成讀物件陣列,依 savedAt 排序渲染)。

// js/favorites.js 讀取收藏
const FAV_KEY = 'dramaweb:fav:v2';
function loadFavList(){
  try{
    const raw = JSON.parse(localStorage.getItem(FAV_KEY) || '[]');
    if (Array.isArray(raw) && raw.length && typeof raw[0] === 'string'){
      return raw.map(id => ({id, savedAt: Date.now()}));
    }
    return Array.isArray(raw) ? raw : [];
  }catch(e){ return []; }
}
function saveFavList(list){
  localStorage.setItem(FAV_KEY, JSON.stringify(list));
}
function render(){
  const list = loadFavList().sort((a,b)=> (b.savedAt||0)-(a.savedAt||0));
  if (!list.length){ $list.html(`<div class="empty">目前沒有收藏的劇集</div>`); return; }
  const map = new Map(SHOWS.map(s => [s.id, s]));
  const items = list.map(o => map.get(o.id)).filter(Boolean);
  $list.html(items.map(cardTemplate).join(''));
}
// 取消收藏
$(document).on('click', '#favCards .fav', function(){
  const id = $(this).closest('.card').data('id');
  const list = loadFavList().filter(o => o.id !== id);
  saveFavList(list);
  render();
});
// 清空
$btnClear.on('click', function(){
  if (!confirm('確定清空全部收藏?')) return;
  saveFavList([]);
  render();
});

2. 心得:版本鍵與結構守護

js/reviews.jsRV_KEY 換成 dramaweb:reviews:v2,讀入時補齊缺欄位。

const RV_KEY = 'dramaweb:reviews:v2';
function loadReviews(){
  try{
    const arr = JSON.parse(localStorage.getItem(RV_KEY) || '[]');
    if (!Array.isArray(arr)) return [];
    return arr.map(x => ({
      id: x.id || ('rv_' + Math.random().toString(36).slice(2)),
      title: x.title || '',
      rating: x.rating || '0.0',
      name: x.name || '匿名',
      content: x.content || '',
      genres: Array.isArray(x.genres) ? x.genres : [],
      createdAt: x.createdAt || new Date().toISOString()
    }));
  }catch(e){ return []; }
}
function saveReviews(list){
  localStorage.setItem(RV_KEY, JSON.stringify(list));
}

驗收

  • 已有資料能正常讀取(相容舊版)。
  • 新增收藏/心得會以新結構保存;清空後再新增也正常。
  • 切換頁面不報錯。

補:快速 Commit 訊息建議

feat(ui): Day13 對話框心得卡+載入更多
docs: Day14 週次小結 README
feat(ux): Day15 微動效(卡片/收藏/chips)
feat(rwd): Day16 手機導覽開關
feat(review): Day17 linkify/@mention 與排版強化
feat(sort): Day18 劇集與心得排序(欄位+方向)
feat(search): Day19 搜尋正規化與模糊比對
chore(storage): Day20 收藏/心得 LocalStorage 版本化與結構升級

上一篇
Day 19:搜尋加強(模糊比對 + 去除全形/空白)
下一篇
Day 21:主題定稿:Y2K 霓虹配色 & Token
系列文
給愛追劇的你:30天互動網站挑戰30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言