一键解决 vue3 + vue-router + keep-alive 页面存留问题

问题描述

在使用vue-router的同时使用keep-alive是一个很常见需求。用户可能会希望某些页面进行keep-alive缓存,以方便在路由之间跳转时保留之前操作的信息。

但是在keep-alive的同时某些情况下我们又不希望它进行缓存,我们希望某些页面是缓存的,而某些页面不进行缓存。这方面的解决方案在网上已经有很多讨论了。

项目搭建

我们首先搭建一个简易项目。我这里使用的是vite+vue3进行项目搭建。

项目创建完成之后进行路由配置,以下是路由配置文件

ts 复制代码
import { createRouter, createWebHistory} from "vue-router";

export const routes = [
    {
        path: '/',
        name: "home",
        component: () => import("@/pages/home.vue"),
        meta: {
            keepAlive: true,
            title: '首页',
        }
    },
    {
        path: '/about',
        name: "about",
        component: () => import("@/pages/about.vue"),
        meta: {
            keepAlive: false,
            title: "关于"
        }
    },
    {
        path: "/config",
        name: "config",
        component: () => import("@/pages/config.vue"),
        meta: {
            keepAlive: true,
            title: "配置"
        },
    }
]
export const router = createRouter({
    history: createWebHistory(),
    routes,
})

然后每个页面都使用这样的简单代码:

html 复制代码
<template>
    <div>
      Home
      <input />
    </div>
</template>

增加一个input用来查看keep-alive效果。

从配置文件可以看出来,我们设置了homeconfig 两个页面是keep-alive的,而中间的about 页面不设置keep-alive

这是App.vue文件初始的状态:

html 复制代码
<template>
  <div>
    <router-link v-for="route in routes" :key="route.name" :to="route.path" style="margin-left: 16px">{{ route.meta.title }}</router-link>
  </div>
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</template>

这是浏览器的显示效果:

方案讨论

常见的方案有以下两种:

  1. 使用两个 router-view 分别显示不同的路由
html 复制代码
<keep-alive>
    <router-view v-if="$route.meta.keepAlive">
        <!-- 这里是会被缓存的视图组件,比如 Home! -->
    </router-view>
</keep-alive>

<router-view v-if="!$route.meta.keepAlive">
    <!-- 这里是不被缓存的视图组件,比如 Edit! -->
</router-view>

经过我的测试发现,这种方法根本没有进行缓存,即使进行了缓存,从逻辑上来说,从不缓存页面 切换到已缓存页面 ,由于v-if的存在,原先的缓存页面也被清除了,所以根本达不到缓存的结果。

  1. 使用keep-alive组件的include参数配置
html 复制代码
<template>
    <router-view v-slot="{ Component }">
        <keep-alive :include="store.cachedRoutes">
            <component :is="Component" />
        </keep-alive>
    </router-view> 
</template>

通过遍历routes数组,将组件存到vuex等地方,并通过keep-aliveinclude参数配置进行keep-alive的组件。这种方案不是说不可以,只是有些繁琐,配置起来需要花费一些时间。

我的方案

我有一种非常简单(且优雅)的方案:不需要配置,不需要双router-view,只需要借助一个小小的key参数。

使用vue的人都知道,在渲染列表的时候,通常需要指定key参数,有时候不指定key参数的代码,lint插件还会报错,浏览器控制台也会显示警告。

大家都只知道key参数可以提高渲染速度,在vue进行diff算法时提供key可以加快diff运算。

但是key参数还有一种神奇用法:强制重新渲染组件(或者说强制重新构建更为贴切)。正是因为diff算法key的比较属于第一优先级的位置,只要组件的key变化了,vue会认为这个组件已经变化,这时将不再判断组件的其他成分,直接构建一个新的组件覆盖原组件。

所以解决keep-alive情况下缓存与不缓存组件共存只需要一行简单的key配置:

html 复制代码
<router-view v-slot="{Component, route}">
  <keep-alive>
    <component :is="Component" :key="route.path + (route.meta.keepAlive ? '' : Math.random())" />
  </keep-alive>
</router-view>

首先通过router-viewv-slot参数拿到route数据。然后在component组件上配置keykeep-alive的页面就使用route-path作为key,而不进行keep-alive的页面就在route-path的基础上加一个随机数。这样就可以保证非keep-alive的页面会强制刷新。这样就解决了困扰我们已久的问题,而且还不需要额外的配置。

我称之为:一键(key)解决方案。

相关推荐
开心工作室_kaic13 分钟前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿32 分钟前
webWorker基本用法
前端·javascript·vue.js
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
getaxiosluo2 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v2 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
栈老师不回家3 小时前
Vue 计算属性和监听器
前端·javascript·vue.js
前端啊龙3 小时前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js
小远yyds4 小时前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
程序媛小果4 小时前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot
小光学长4 小时前
基于vue框架的的流浪宠物救助系统25128(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
数据库·vue.js·宠物