狀態緩存的藝術:KeepAlive
當你在 SPA 中切換路由時,預設行為是:銷毀舊組件,掛載新組件。 這意味著你在表單裡輸入的資料、滾動條的位置、透過 API 抓取的清單,全部都會消失。
如果你想保留這些狀態,你需要 <keep-alive>。
但在 Vue Router 4 中,要把 KeepAlive 加進去,可是有一套非常嚴格的規則。
一、 黃金三角:正確的包裹順序
這是一個經典的面試題,也是無數開發者的惡夢:當我想同時擁有「轉場動畫」與「頁面緩存」時,該怎麼包?
請死記這個順序:
- 最外層:
RouterView(提供 Slot) - 第二層:
Transition(處理動畫) - 第三層:
KeepAlive(處理緩存) - 最內層:
Component(渲染組件)
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<keep-alive>
<component :is="Component" />
</keep-alive>
</transition>
</router-view>只要順序錯了(例如把 Transition 包在 KeepAlive 裡面),動畫就會失效,或者緩存會壞掉。
二、 精準控制:Include 與 Exclude
你通常不會想要緩存「所有」的頁面(那樣記憶體會爆炸)。你只想緩存列表頁,但不想緩存詳情頁。
這時就要用到 include 屬性。
<keep-alive include="UserList,ProductList">
<component :is="Component" />
</keep-alive>致命雷區️:組件名稱 (Component Name)
include 匹配的是 組件定義中的 name 選項,而不是路由的 name,也不是檔名!
Vue 3 SFC (單檔組件) 如何定義 name?
Vue 3.3+ (script setup): 檔名即為預設名稱。但最好還是明確定義:
javascriptdefineOptions({ name: "UserList", });Vue 2 / Vue 3 Option API:
javascriptexport default { name: "UserList", };
如果你的組件沒有 name,或者 name 與 include 不一致,緩存絕對不會生效。這是 90% 的人會踩到的坑。
三、 生命週期 (Lifecycle)
被緩存的組件 不會 被銷毀 (Unmounted),所以 onUnmounted 不會觸發;再次進入時,onMounted 也不會觸發。
取而代之的是兩個專屬 Hook:
onActivated: 每次進入組件時觸發 (包含初次掛載)。onDeactivated: 每次離開組件時觸發。
實戰應用
假設你在做一個新聞列表:
import { onActivated } from "vue";
onActivated(() => {
// 每次回到這個頁面,檢查有沒有新消息
// 但不要重抓整個列表 (因為列表已經被緩存了)
checkNewNotifications();
});四、 複雜場景:基於 Route Meta 的控制
如果你的應用很複雜,用 include="String" 寫死可能不夠靈活。我們可以利用 route.meta:
1. 定義 Meta
// router/index.js
{
path: '/list',
component: UserList,
meta: { keepAlive: true } // 標記需要緩存
}2. 在 RouterView 使用 v-if
這個技巧非常實用:我們可以寫兩個 <component>,一個有包 KeepAlive,一個沒有。
<router-view v-slot="{ Component, route }">
<!-- 情況 A: 需要緩存 -->
<keep-alive>
<component :is="Component" v-if="route.meta.keepAlive" :key="route.path" />
</keep-alive>
<!-- 情況 B: 不需要緩存 -->
<component :is="Component" v-if="!route.meta.keepAlive" :key="route.path" />
</router-view>這樣你就可以完全透過路由配置來控制緩存行為了!
總結
- 結構:
RouterView > Slot > Transition > KeepAlive > Component。 - 名稱:
include對應的是 組件的 name (defineOptions)。 - 生命週期:使用
onActivated來處理「每次進入」的邏輯。
掌握了這兩章 (轉場與緩存) 後,你的 SPA 體驗已經非常接近原生 App 了。下一章,我們將探討如何讓網頁載入更快——路由懶加載。