在開發前端互動工具時,我們常遇到一個尷尬的現象:使用者開心地輸入了藥品名稱、開瓶日期與效期天數,甚至排好了全天的用藥時間表;但只要不小心按到 F5 重新整理,或是把頁面關掉重新開啟,所有的資料就瞬間「灰飛煙滅」。
一個成熟的 Web App,絕對不能讓使用者重複進行無意義的輸入。
在 Day 26 與 Day 27 這兩篇文章中,我們要為 [Tool 3 用藥時間表] 與 [Tool 4 開瓶倒數追蹤] 建立全站的資料記憶機制。今天這篇(上集),我們將聚焦於資料寫入與物件序列化(Serialization),透過 Web Storage API 的 localStorage.setItem() 與 JSON.stringify(),將陣列資料永久儲存在使用者的瀏覽器中!
在 Web 開發中,若不需要透過 Server 或 API 存取資料庫,LocalStorage 是實作單機版資料持久化(Persistence)的最佳選擇。
"[object Object]"。為了在 LocalStorage 中儲存複雜的結構化資料(如包含 ID、名稱、日期的藥品清單陣列),我們必須使用 JSON.stringify() 將 JavaScript 物件轉換為 JSON 格式的文字字串。
我們在 /tool4-timer.js 中處理輸入校正、封裝全新物件,並透過 saveAndRender() 執行序列化寫入:
/tool4-timer.js
// 2. 新增追蹤項目
btnAddTimer.addEventListener("click", () => {
const nameInput = document.getElementById("item-name");
const dateInput = document.getElementById("open-date");
const expiryInput = document.getElementById("expiry-days");
const name = nameInput.value.trim();
const dateStr = dateInput.value;
// 讀取效期天數,若未輸入或小於 1 則預設為 28 天
const expiryDays = parseInt(expiryInput.value, 10) > 0 ? parseInt(expiryInput.value, 10) : 28;
if (!name || !dateStr) {
alert("請輸入藥品名稱與開瓶日期!");
return;
}
const newItem = {
id: Date.now(),
name: name,
openDate: dateStr,
expiryDays: expiryDays // ✨ 儲存自訂的效期天數
};
timerItems.push(newItem);
saveAndRender();
// 清空輸入框並還原預設天數
nameInput.value = "";
dateInput.value = "";
expiryInput.value = "28";
});
// 4. 儲存與渲染
function saveAndRender(){
localStorage.setItem("med_timer_list", JSON.stringify(timerItems));
renderTimers();
}
/tool3-schedule.js
// 5. 儲存與渲染
function saveAndRender(){
localStorage.setItem("med_schedule_list", JSON.stringify(medList));
renderSchedule();
}
Date.now() 建立不重複唯一識別碼(Unique ID)在新增 newItem 物件時,我們使用 id: Date.now() 產生當下的毫秒時間戳記。這是一種極為高效且輕量的 ID 產生方式,能確保後續進行單項刪除或精準尋找時,不會因藥品名稱相同而誤刪其他項目。
parseInt() 進行防衛型數值校正輸入框取得的數值皆為字串型態,透過 parseInt(expiryInput.value, 10) 轉為整數。
利用三元運算子 parseInt(...) > 0 ? parseInt(...) : 28 進行門檻校正,確保使用者輸入空值、0 或負數時,能自動降級回歸安全的預設值 28 天,維持資料欄位的合規性。
saveAndRender() 封裝我們將 localStorage.setItem() 與 renderTimers() 統一收合進 saveAndRender() 函式中。
這樣設計的好處是:不管是「新增項目」、「修改項目」還是「刪除項目」,只要資料狀態發生改變,呼叫 saveAndRender() 就能同步確保資料庫更新與介面重繪,維持 UI 與 State 的絕對一致。
JSON.stringify() 物件序列化在 localStorage.setItem("med_timer_list", JSON.stringify(timerItems)) 中,JSON.stringify() 扮演了關鍵的轉譯橋樑,將記憶體中的 JavaScript 陣列結構拍扁成符合 LocalStorage 規格的文字字串,實現長久的硬碟儲存。
今天我們完成了 [Tool 3] 與 [Tool 4] 的資料序列化與 LocalStorage 寫入機制,徹底解決了網頁重新整理後資料遺失的痛點,讓應用程式具備了基本且健全的狀態持久化能力。
然而,將資料成功存入瀏覽器只完成了一半!在明天的 [Day 27] 中,我們將進行 [【全站記憶】 LocalStorage 應用(下):用 JSON.parse() 讀取歷史紀錄與一鍵清空 LocalStorage 資料庫],實作頁面初始化時的反序列化載入與全防呆的一鍵清空機制。