跳至主要內容
Skip to content

狀態緩存的藝術:KeepAlive

當你在 SPA 中切換路由時,預設行為是:銷毀舊組件,掛載新組件。 這意味著你在表單裡輸入的資料、滾動條的位置、透過 API 抓取的清單,全部都會消失。

如果你想保留這些狀態,你需要 <keep-alive>

但在 Vue Router 4 中,要把 KeepAlive 加進去,可是有一套非常嚴格的規則。


一、 黃金三角:正確的包裹順序

這是一個經典的面試題,也是無數開發者的惡夢:當我想同時擁有「轉場動畫」與「頁面緩存」時,該怎麼包?

請死記這個順序:

  1. 最外層:RouterView (提供 Slot)
  2. 第二層:Transition (處理動畫)
  3. 第三層:KeepAlive (處理緩存)
  4. 最內層:Component (渲染組件)
html
<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 屬性。

html
<keep-alive include="UserList,ProductList">
  <component :is="Component" />
</keep-alive>

致命雷區️:組件名稱 (Component Name)

include 匹配的是 組件定義中的 name 選項,而不是路由的 name,也不是檔名!

Vue 3 SFC (單檔組件) 如何定義 name?

  1. Vue 3.3+ (script setup): 檔名即為預設名稱。但最好還是明確定義:

    javascript
    defineOptions({
      name: "UserList",
    });
  2. Vue 2 / Vue 3 Option API:

    javascript
    export default {
      name: "UserList",
    };

如果你的組件沒有 name,或者 name 與 include 不一致,緩存絕對不會生效。這是 90% 的人會踩到的坑。


三、 生命週期 (Lifecycle)

被緩存的組件 不會 被銷毀 (Unmounted),所以 onUnmounted 不會觸發;再次進入時,onMounted 也不會觸發。

取而代之的是兩個專屬 Hook:

  • onActivated: 每次進入組件時觸發 (包含初次掛載)。
  • onDeactivated: 每次離開組件時觸發。

實戰應用

假設你在做一個新聞列表:

javascript
import { onActivated } from "vue";

onActivated(() => {
  // 每次回到這個頁面,檢查有沒有新消息
  // 但不要重抓整個列表 (因為列表已經被緩存了)
  checkNewNotifications();
});

四、 複雜場景:基於 Route Meta 的控制

如果你的應用很複雜,用 include="String" 寫死可能不夠靈活。我們可以利用 route.meta

1. 定義 Meta

javascript
// router/index.js
{
  path: '/list',
  component: UserList,
  meta: { keepAlive: true } // 標記需要緩存
}

2. 在 RouterView 使用 v-if

這個技巧非常實用:我們可以寫兩個 <component>,一個有包 KeepAlive,一個沒有。

html
<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>

這樣你就可以完全透過路由配置來控制緩存行為了!


總結

  1. 結構RouterView > Slot > Transition > KeepAlive > Component
  2. 名稱include 對應的是 組件的 name (defineOptions)。
  3. 生命週期:使用 onActivated 來處理「每次進入」的邏輯。

掌握了這兩章 (轉場與緩存) 後,你的 SPA 體驗已經非常接近原生 App 了。下一章,我們將探討如何讓網頁載入更快——路由懶加載

下一章:效能優化:路由懶加載