iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0
Modern Web

微光採集瓶:用 Vue 3 打造每日美好記錄網頁系列 第 14 篇

【Day 14】別讓記憶消失:用 LocalStorage 實現資料持久化儲存

  • 分享至 

  • xImage
  •  

現在我們已經可以讓光珠被採集至玻璃瓶中,但如果刷新了頁面,裡面的光珠就會馬上消失,沒有辦法真的儲存下來或是被記得,所以今天要說明 LocalStorage 並使用它來處理這個問題。

一、LocalStorage 是什麼?

在沒有串接後端資料庫的情況下,網頁中的 JavaScript 變數(例如我們的 gems = ref([]))都是暫存在瀏覽器的記憶體裡。一旦關閉分頁或按下重新整理,記憶體被釋放,所有採集好的光珠就會瞬間消失,像是沒存在過。

為了把資料保留在使用者自己的電腦上,瀏覽器提供了原生儲存機制:Web Storage API,其中最常用的就是 LocalStorage。

你可以把 LocalStorage 想像成瀏覽器提供給每個網站專屬的「本地小抽屜」:

  • 持久保存:除非使用者主動清理瀏覽器快取,或是用程式碼去刪除它,否則就算關閉瀏覽器、重開機,裡面的資料都會一直在。
  • 以 Key-Value 儲存:就像置物櫃一樣,放進去時要貼上標籤名稱(Key),拿出來時憑著標籤名稱取回(Value)。
  • 只吃純字串:這是很重要的一點。LocalStorage 只接受純文字,它看不懂 JavaScript 的物件或陣列。
  • 儲存容量:通常每個網域有約 5MB 的空間。拿來存放我們光珠的簡短文字與顏色,空間應該是很夠了。

二、存取物件的關鍵轉換:JSON.stringify 與 JSON.parse

既然 LocalStorage 只能存純文字,那我們該怎麼把裝滿光珠物件的陣列 [ { id: 1, note: '...', color: '...' }, ... ] 存進去?

這時候就需要透過 JavaScript 內建的 JSON 工具來進行「打包」與「拆封」:

1. 寫入:JSON.stringify()(打包成字串)

當我們要存入光珠陣列時,必須先用 JSON.stringify() 把 JavaScript 的陣列物件轉換成符合格式的純文字字串:

const gemsArray = [{ id: 1, note: '散步吹風很舒服', color: '#E3B341' }]
const stringData = JSON.stringify(gemsArray)

// 存進 LocalStorage,標籤取名為 'store_gems'
localStorage.setItem('store_gems', stringData)

2. 取出:JSON.parse()(還原回物件陣列)

當下次打開網頁要讀取時,從 LocalStorage 拿出來的只是一串文字,必須透過 JSON.parse() 把字串「解壓縮」變回 Vue 看得懂的陣列:

const savedData = localStorage.getItem('store_gems')

// 如果storage裡面有東西,就解析還原;如果是空的,就給一個空陣列 []
const gemsList = savedData ? JSON.parse(savedData) : []

三、在 Vue 3 中整合:初始化讀取與 watch 自動同步

理解了原理後,接回 Vue 3 的架構其實非常簡單,我們不需要在每次點擊「採集按鈕」時手動寫一次存檔,而是交給 Vue 的響應式與監聽機制。

打開 src/components/GemJar.vue,在 <script setup> 裡做兩處調整:

1. 初始化讀取:從 LocalStorage 恢復光珠

改寫原本宣告 gems 的那一行:

// 先到 LocalStorage 抓抓看有沒有以前存過的光珠
const savedGems = localStorage.getItem('store_gems')

// 如果有存檔就解析出來當預設值,沒有就初始化為空陣列
const gems = ref(savedGems ? JSON.parse(savedGems) : [])

2. 自動同步:用 watch 深度監聽

引入 Vue 的 watch,只要 gems 陣列有任何變動(無論是新放入光珠,還是未來要修改內容),就自動把最新陣列轉成字串存進 LocalStorage:

import { ref, watch } from 'vue'

// 監聽 gems 陣列
watch(
  gems,
  (newGems) => {
    localStorage.setItem('store_gems', JSON.stringify(newGems))
  },
  { deep: true } // 深度監聽:物件內部的屬性改變也能抓到
)

為什麼要加 { deep: true }?
gems 是一個包含多個物件的陣列。如果沒有加上 deep: true,Vue 預設只會在陣列本身的長度改變(例如 push、splice)時觸發監聽;未來如果我們直接修改某顆光珠裡面的文字或顏色時,就可能無法觸發存檔。開啟「深度監聽」可以確保陣列內部的任何修改都會自動同步進 LocalStorage。

四、成果驗證與開發者工具檢查

存檔後回到瀏覽器測試:

  1. 基本持久化測試:
  • 在畫面上採集 2~3 顆不同顏色與心情的光珠。
  • 按下瀏覽器的重新整理按鈕,或者直接關閉分頁再重新打開。
  • 確認原本採集的光珠依然在瓶中相同位置,而且點擊預覽卡片也能正常讀出當時的文字。
  1. 打開 DevTools 檢查實體資料:
  • 在頁面按右鍵選擇「檢查」,切換到 Application 分頁。
  • 在左側選單找到 Storage > Local storage,點擊你的本機網址。
  • 右側表格就會看見 Key 名稱為 store_gems,而 Value 則完整儲存著我們轉成字串的光珠資料。

點我看影片:本地儲存成果影片展示
https://ithelp.ithome.com.tw/upload/images/20260928/20178067qPwYlaero8.png

今日小結

  • 認識 LocalStorage:理解瀏覽器原生本地存儲的特性與限制(以字串格式持久保留資料於使用者本機端)。
  • 資料序列化:了解 JSON.stringify()(物件轉字串)與 JSON.parse()(字串還原物件)的轉換關鍵。
  • 資料驅動存儲:透過 Vue 3 的 watch 搭配 { deep: true } 實現自動持久化同步,不用在每個按鈕事件裡手動呼叫儲存函式。

明日預告

現在光珠已經可以永久安全地留在瓶子裡了!
但日記的儀式感來自於「每天的記錄」。如果不小心打錯字想反悔怎麼辦?
明天(Day 15),我們要實作「當日微光修改與過期鎖定」,替光珠加上日期標籤,今天放進去的微光允許重新編輯或撤回,但過了今天,它就會化作唯讀的珍貴回憶,被鎖定住無法更改。


上一篇
【Day 13】點亮記憶:光珠懸浮回饋與點擊預覽卡片
下一篇
【Day 15】時間的設置:當日編輯撤回與歷史過期鎖定
系列文
微光採集瓶:用 Vue 3 打造每日美好記錄網頁 共 19 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言