带你看懂Vue3 KeepAlive 及实际应用

带你看懂Vue3 KeepAlive 及实际应用

前言

在整理前端知识时,觉得vue3的keepAlive使用上与vue2略有不同,并且vue3可以通过自定义Hooks更好更方便地使用keepAlive。因此决定写一篇博客来记录和讲解下这个我们开发中一定会遇到的知识点。

keepAlive的概念

keepAlive是vue中的一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例,简单理解就是,当我们路由切换到新的路由再切换回来后,原来的页面能保持原本的实例,并不会被销毁。也就是不会再次触发createmounted这些生命周期钩子函数,取而代之的是onActivatedonDeactivated两个钩子函数,具体用法将在后面讲解。

基本使用

keepAlive上的prop共有三个参数include、exclude、max,具体使用示例如下 (1)include被包涵的组件将能够被缓存

xml 复制代码
<!-- 以英文逗号分隔的字符串 -->
<KeepAlive include="a,b">
  <component :is="view" />
</KeepAlive>

<!-- 正则表达式 (需使用 `v-bind`) -->
<KeepAlive :include="/a|b/">
  <component :is="view" />
</KeepAlive>

<!-- 数组 (需使用 `v-bind`) -->
<KeepAlive :include="['a', 'b']">
  <component :is="view" />
</KeepAlive>

它会根据组件的 name 选项进行匹配,所以组件如果想要条件性地被 KeepAlive 缓存,就必须显式声明一个 name 选项
在 3.2.34 或以上的版本中,使用 <script setup> 的单文件组件会自动根据文件名生成对应的 name 选项,无需再手动声明。

(2)exclude 所包涵的组件将不会被缓存 (3)max 最多可以缓存多少个组件实例

ruby 复制代码
<KeepAlive :max="10">
  <component :is="view"></component>
</KeepAlive>

高级用法

上面我们已经介绍过了keepAlive的基本使用场景,但是在实际应用中,我们更多地是与路由组件相结合来使用,那么具体怎么用呢?

(1)首先我们在定义路由时需要在路由配置中加入配置项,判断当前路由是否需要被缓存。

css 复制代码
 {
        path: '/',
        name: 'home',
        meta: {
            keepAlive: true,
            deepth:1,
        },
        component: () => import('@/pages/home/home.vue'),
    },

(2)在app.vue中修改router-view的配置,增加keep-alive,通过上面路由中的meta值来判断当前组件是否需要缓存。

ini 复制代码
 <router-view v-slot="{ Component }">
    <keep-alive :include="includeRoute">
        <component
            :is="Component"
            :key="$route.name"
            v-if="$route.meta.keepAlive"
        />
    </keep-alive>
    <component
        :is="Component"
        :key="$route.name"
        v-if="!$route.meta.keepAlive"
    />
</router-view>

(3)通过deepth判断includeRoute中需要被缓存的页面,及时销毁无需缓存的页面。同过比对deepth,也就是页面路由的深度,这样当返回到最外层路由时,可以销毁掉深层次的无用的页面缓存。

ini 复制代码
//keepAlive路由数组
let pathDeepArr: any = [];
// 监听当前路由的name变化
watch(
    () => router.currentRoute.value,
    (newValue: any) => {
        if (newValue.meta.keepAlive) {
            let pathArr = pathDeepArr.filter((item: any) => {
                return item.name == newValue.name;
            });
            //去重,存在就不添加
            if (pathArr.length == 0) {
                pathDeepArr.push({
                    name: newValue.name,
                    deepth: newValue.meta.deepth,
                });
            }

            let tempArr = pathDeepArr.filter((item: any) => {
                return (
                    item.deepth < newValue.meta.deepth ||
                    item.deepth == newValue.meta.deepth
                );
            });
            pathDeepArr = tempArr;
            includeRoute.value =
                tempArr.length > 0
                    ? tempArr.map((item: any) => item.name)
                    : ['home'];
        }

        if (newValue.name == 'login') {
            includeRoute.value = [];
        }
    },
    { immediate: true },
);

通过上面的步骤,就能将keep-alive与路由完美的结合,那么还有个问题,比如我们在访问列表页时,页面发生了滚动,当我们点击列表中的某一条进入到详情页再返回后,会发现虽然页面被缓存了,数据也都在,但是滚动条到位置跑到了最顶端,那么我们该如何解决这个问题呢?接下来我将用一个hooks解决这个问题。

自定义Hooks

上面提到了keepalive多了两个生命周期的钩子onActivatedonDeactivated,那么我们就可以在页面滚动的时候记住滚动的距离scrollTop,当页面返回,也就是onActivated的时候,滚动到上次滚动到位置。

hooks代码如下:

ini 复制代码
import { ref, onActivated } from 'vue';
const keepAliveHook = () => {
    const scrollRef = ref<any>(null);
    const scrollTop = ref(0);
    //再次返回页面时保持原先滚动的位置
    onActivated(() => {
        scrollRef.value.scrollTop = scrollTop.value;
    });
    //页面滚动保留滚动高度
    const onScrollBody = () => {
        scrollTop.value = scrollRef.value.scrollTop || 0;
    };

    return { onScrollBody, scrollRef };
};

export default keepAliveHook;

在页面中使用:

xml 复制代码
<template>
 <div class="home-container" ref="scrollRef" @scroll="onPageScroll">
 </div>
 </template>

<script lang="ts" setup>
import keepAliveHook from '@/hooks/keepAliveHook';

const { onScrollBody, scrollRef } = keepAliveHook();
//页面滚动
const onPageScroll = () => {
    onScrollBody();
}
</script>

这样就能解决返回页面时无法自动滚动到上次位置到问题了。

最后

以上是我在vue中使用keepalive的一些应用场景,以及经验总结,欢迎掘友们提出更好更多其他用法😊

相关推荐
GIS程序媛—椰子19 分钟前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_00125 分钟前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端28 分钟前
Content Security Policy (CSP)
前端·javascript·面试
木舟100932 分钟前
ffmpeg重复回听音频流,时长叠加问题
前端
王大锤439143 分钟前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang
我血条子呢1 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
黎金安1 小时前
前端第二次作业
前端·css·css3
啦啦右一1 小时前
前端 | MYTED单篇TED词汇学习功能优化
前端·学习
半开半落1 小时前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt