最近使用 nuxt@3.x
版本做SEO最佳化專案比較多,之前也踩坑過,所以記錄一下在 nuxt3
中路由快取的正確使用方法,本人也之前在GitHub社群中提交過反饋問題,最後是在 3.8.2
版本解決了路由快取問題。下面講解如何正確使用keepalive做到頁面快取,元件快取。
# 環境版本如下
node # 21.4.0
nuxt # 3.12.3
vue # latest 目前最新版本 3.4.*
頁面快取
keepalive 我們知道都是用來快取元件 在元件解除安裝的時候 並不去真正意義上的銷燬,而是隱藏掉。等再次掛載的時候再把它顯示出來。其元件的狀態保持原有的狀態,並不會初始化。寫多了 vue
專案的小夥伴們,大部分透過路由檔案( src/router.js
)定義 name
值,再去 router-view
元件裡包裹 keepalive
元件去判斷 路由裡面的 name
值去使用。但是在 nuxt
框架內不需要這麼複雜的操作。
- app.vue檔案內容
<!-- app.vue -->
<template>
<div>
<!-- 最新版vue支援的語法,老版本可能提示錯誤 -->
<NuxtPage :keepalive />
</div>
</template>
<script lang="ts" setup>
// keepalive 所需的引數 指定name值為index 的頁面 進行快取
const keepalive = {
include: ["index"],
};
</script>
- pages資料夾
pages
├─index.vue # 若元件未定義name值 則為 檔名 index
└─user.vue # name為user
- index.vue檔案內容
<template>
<div>index</div>
<p>data: {{ data }}</p>
<p>
<button @click="data++">+1</button>
<button @click="data--">-1</button>
</p>
<p class="links">
<NuxtLink to="/user">user Page</NuxtLink>
</p>
</template>
<script setup lang="ts">
const data = ref(0);
</script>
專案啟動路徑為 http://localhost:3000/
的時候,此時,在元件內操縱 data
的值變化,再去跳轉 http://localhost:3000/user
時,再跳回 http://localhost:3000/
, data
的值不會初始化,而是切換 /user
路由前頁面的狀態。此時使用 onActivated
api來監聽元件被啟用。
<script lang="ts" setup>
onActivated(() => {
console.log("onActivated 頁面啟用了!");
});
</script>
- 路徑複雜的請使用
defineOptions
指定元件name值,以免使用路由快取失敗!
例如:pages/userData.vue,pages/news/detail,pages/news/[id].vue。這幾個路徑過於複雜,在 NuxtPage
元件中難以使用 include
屬性值去判斷快取條件,所以需要在頁面檔案中宣告該頁面的元件 name
值。
<!-- pages/index.vue -->
<script setup lang="ts">
defineOptions({
name: "IndexPage",
});
</script>
<!-- pages/news/detail.vue -->
<script setup lang="ts">
defineOptions({
name: "newsDetail",
});
</script>
<!-- app.vue -->
<template>
<div>
<NuxtPage :keepalive />
</div>
</template>
<script lang="ts" setup>
const keepalive = {
include: ["IndexPage","newsDetail"],
// 對應 pages/index.vue ,pages/news/detail.vue 中的 name 值 快取路由
};
</script>
元件快取
如果在頁面中,使用了v-if
指令來控制元件顯示,如何保證元件資料不被銷燬。當然還是使用keepalive
元件。假設我們在components
檔案中定義元件,會自動全域性匯入,無需引用。
components
├─Val
│ └─Input.vue # 若元件未定義name值 則為 檔名 Input
├─Counter.vue # 若元件未定義name值 則為 檔名 Counter
└─TextTip.vue # name 為 TextTip
<!-- components/Counter.vue -->
<template>
<div class="counter">
<h2>counter</h2>
<p>data:{{ data }}</p>
<p>
<button @click="data++">+1</button>
<button @click="data--">-1</button>
</p>
</div>
</template>
<script lang="ts" setup>
const data = ref(0);
</script>
<style scoped>
.counter {
padding: 20px;
}
</style>
<!-- components/TextTip.vue -->
<template>
<div class="text-tip">
<h2>text-tip</h2>
<p>text: {{ text }}</p>
<p>
<button @click="text += '1'">add Text</button>
</p>
</div>
</template>
<script lang="ts" setup>
const text = ref("text-1");
</script>
<!-- pages/index.vue -->
<template>
<div>index</div>
<p>
<button @click="showCounter = !showCounter">
{{ !showCounter ? "顯示Counter" : "顯示TextTip" }}
</button>
</p>
<hr />
<KeepAlive :include="keep.include">
<Counter v-if="showCounter" />
<TextTip v-else />
</KeepAlive>
</template>
<script setup lang="ts">
const showCounter = ref(false);
const keep = {
include: ["Counter"],
};
</script>
此時點選 顯示Counter
按鈕,在 Counter
元件中操作內部資料改變 data:5
,點選按鈕再去切換元件顯示隱藏,會發現 Counter
元件並不會銷燬掉之前的值 data:5
,而TextTip元件在操作內部的資料改變後切換 隱藏/顯示
後, text
資料是初始化的值 text-1
。
- 注意components檔案定義的元件name值
components/Counter.vue
, components/Val/Input.vue
的 name
值nuxt自動會給元件的name值取為檔名 Counter
, Input
。而在元件自動匯入的時候卻是使用 <Counter />
, <ValInput />
。會有點迷惑,所以請在使用 <KeepAlive>
元件包裹來快取狀態,請務必使用 defineOptions
指定元件的name值。
<!-- components/Val/Input.vue -->
<template>
<div class="input-warpper">
<h2>Input</h2>
<input v-model="val" />
</div>
</template>
<script lang="ts" setup>
const val = ref("");
defineOptions({
name: "ValInput"
})
</script>
<style>
.input-warpper {
margin: 20px;
}
</style>
或者使用 export default { name:'xxx' }
來指定元件的name值,不使用 setup
語法。
<!-- components/Val/Input.vue -->
<template>
<div class="input-warpper">
<h2>Input</h2>
<input v-model="val" />
</div>
</template>
<script lang="ts" setup>
const val = ref("");
</script>
<script lang="ts">
export default {
name: "ValInput"
}
</script>
<style>
.input-warpper {
margin: 20px;
}
</style>
案例地址
點選這裡跳轉程式碼案例,來除錯 keepalive 頁面快取 和 元件快取
推薦環境版本: node v21.4.0
, nuxt v3.12.*
, 使用 pnpm 安裝依賴
。