本文 AI 產出,尚未審核

Vue3 – 效能與最佳化:keep-alive 緩存

簡介

在單頁應用(SPA)中,切換路由或切換大量子組件時,若每次都重新執行掛載、銷毀的生命週期,會造成不必要的效能損耗,尤其在手機或低階裝置上更為明顯。Vue 3 提供的 <keep-alive> 組件,讓開發者可以 將已經渲染過的組件實例緩存起來,在下次需要時直接復用,省去重新渲染的成本。

本篇文章將從概念、使用方式、實務範例、常見陷阱與最佳實踐,完整說明 keep-alive 在 Vue 3 中的運作原理與最佳化策略,幫助初學者到中級開發者快速上手並在實際專案中正確應用。


核心概念

1. keep-alive 是什麼?

<keep-alive> 是一個 抽象組件(abstract component),它不會產生自己的 DOM,而是把包裹的子組件「暫存」起來。被暫存的組件會保留其 data、computed、watcher、狀態(state)以及 DOM 節點,只會觸發 activated / deactivated 兩個生命週期鉤子,而不會走 createdmountedunmounted

2. 何時使用 keep-alive

  • 頁籤切換:如「商品列表」與「購物車」頻繁切換,保持列表的滾動位置與已載入資料。
  • 表單編輯:使用者在多步驟表單間跳來跳去,避免已填寫的資料遺失。
  • 大型列表或圖表:渲染成本高的組件,切換時只需要顯示/隱藏即可。

3. 基本語法

<keep-alive>
  <component :is="currentView"></component>
</keep-alive>
  • currentView 為動態切換的組件名稱或元件物件。
  • 只要 <keep-alive> 包住的子組件符合條件,就會被緩存。

4. 控制緩存的屬性

屬性 說明 範例
include 只緩存符合名稱或正則的組件 <keep-alive include="User,Settings">
exclude 排除不想緩存的組件 <keep-alive :exclude="/^Admin/">
max 緩存的最大實例數,超過會依 FIFO 刪除最舊的 <keep-alive :max="5">

5. 生命週期鉤子

  • activated:組件從緩存中被取出、重新顯示時呼叫。
  • deactivated:組件被放入緩存、隱藏時呼叫。

注意mountedunmounted 只會在第一次掛載與最終銷毀時觸發。


程式碼範例

範例 1:最簡單的頁籤切換

<!-- App.vue -->
<template>
  <div>
    <button @click="current = 'Home'">Home</button>
    <button @click="current = 'Profile'">Profile</button>

    <keep-alive>
      <component :is="current"></component>
    </keep-alive>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import Home from './components/Home.vue'
import Profile from './components/Profile.vue'

const current = ref('Home')
</script>
  • 說明:切換 HomeProfile 時,兩個組件的狀態會被保留。若不加 <keep-alive>,每次切換都會重新呼叫 createdmounted

範例 2:使用 include / exclude 控制緩存

<keep-alive include="Dashboard,Settings" :exclude="/^Admin/">
  <router-view></router-view>
</keep-alive>
  • 說明:只會緩存路由名稱為 DashboardSettings 的組件;所有以 Admin 開頭的路由則不會被緩存,適合保護敏感頁面不留下快取。

範例 3:設定最大緩存數量 max

<keep-alive :max="3">
  <router-view></router-view>
</keep-alive>
  • 說明:最多同時保留 3 個組件的實例,當第 4 個被加入時,最早加入的會被自動銷毀(觸發 unmounted),防止記憶體過度佔用。

範例 4:利用 activated / deactivated 執行自訂邏輯

// Detail.vue
export default {
  name: 'Detail',
  data() {
    return { scrollTop: 0 }
  },
  activated() {
    // 從緩存中恢復時,還原滾動位置
    this.$nextTick(() => {
      this.$el.scrollTop = this.scrollTop
    })
  },
  deactivated() {
    // 隱藏前先記錄滾動位置
    this.scrollTop = this.$el.scrollTop
  }
}
  • 說明:在列表頁返回細節頁時,使用者的滾動位置不會被重置,提升使用體驗。

範例 5:結合 v-showkeep-alive 的最佳化

<keep-alive>
  <MyHeavyComponent v-show="showHeavy"></MyHeavyComponent>
</keep-alive>

<button @click="showHeavy = !showHeavy">Toggle Heavy</button>
  • 說明v-show 只改變 display,不會觸發掛載/銷毀;配合 keep-alive,在切換顯示狀態時完全不會重新渲染,適合「一次渲染、頻繁切換」的情境。

常見陷阱與最佳實踐

陷阱 可能的影響 解決方案
緩存過多導致記憶體飽和 大型表格或圖表持續累積,瀏覽器記憶體使用量急升 使用 max 限制緩存數量,或在不需要時手動 unmountv-if
狀態未重置 表單切換後仍保留舊資料,造成錯誤提交 deactivated 中手動清除或在 activated 中重新初始化
與 Vue Router 搭配時忘記 key 同一路由但不同參數的組件仍被視為同一緩存實例 <router-view> 加上 :key="$route.fullPath",確保每個參數組合都有獨立緩存
使用 keep-alive 包住非組件 會產生警告或無效緩存 確保 <keep-alive> 只包住 具名或匿名組件,不要直接包住普通 HTML 標籤
誤用 include / exclude 正則 正則寫錯導致所有組件皆被排除或全部緩存 測試正則表達式,或改用陣列形式 include=['Home','Profile'] 以避免語法錯誤

最佳實踐

  1. 先評估成本:只有在「渲染成本高」或「切換頻繁」的情況下才使用 keep-alive
  2. 搭配 max:避免無限制緩存,特別是移動端。
  3. 使用 activated / deactivated 處理需要在顯示/隱藏時執行的副作用(如 API 請求、滾動位置、計時器)。
  4. 在路由層面加 key:保證不同參數的路由能得到獨立的快取。
  5. 定期檢測記憶體:使用 Chrome DevTools 的 Performance / Memory 面板觀察快取是否過大。

實際應用場景

1. 電商商品列表與商品詳情

使用 keep-alive 緩存商品列表頁,使用者在商品詳情與列表間切換時,列表的 滾動位置、已載入的分頁資料 皆不會重新請求,減少 API 呼叫與頁面閃爍。

2. 多步驟表單(Wizard)

在每一步都使用 keep-alive,使用者可隨意前後切換,已填寫的欄位會自動保留,且不必在每次切換時重新驗證或重新取得遠端資料。

3. 管理後台的圖表儀表板

大型圖表(如 ECharts、Highcharts)渲染成本高,將圖表組件放入 <keep-alive>,切換不同儀表板時,只需顯示/隱藏,避免重繪造成卡頓。

4. 手機端的 SPA

手機裝置記憶體較受限,使用 max 限制緩存數量,同時在不活躍的頁面使用 v-if 釋放資源,兼顧效能與使用者體驗。


總結

<keep-alive> 是 Vue 3 中用來 提升切換效能、減少不必要重新渲染 的強大工具。透過 includeexcludemax 等屬性,我們可以精細控制哪些組件需要被緩存、緩存多少實例;而 activated / deactivated 生命週期則提供在「取出」與「放入」快取時執行自訂邏輯的能力。

在實際開發中,先評估渲染成本設定合理的緩存上限,並善用生命週期鉤子清理或重置狀態,就能在不犧牲記憶體的前提下,為使用者帶來更流暢的操作體驗。希望本篇文章能讓你快速掌握 keep-alive 的核心概念與最佳實踐,並在專案中靈活運用,打造高效能的 Vue 3 應用。祝開發順利!