nuxt3正確使用keepalive頁面快取元件快取

阿政想暴富發表於2024-07-10

最近使用 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.vuepages/news/detailpages/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.vuecomponents/Val/Input.vuename 值nuxt自動會給元件的name值取為檔名 CounterInput 。而在元件自動匯入的時候卻是使用 <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 安裝依賴

相關文章