最近使用
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 安装依赖

标签: none

添加新评论