vue 路由缓存
Vue Router 允许你在你的应用中创建多个视图,并根据路由来动态切换这些视图。
默认情况下,当你从一个路由切换到另一个路由时,Vue Router 会销毁前一个路由的组件实例并创建新的组件实例。然而,有时候你可能希望保持一些页面的状态,以便用户在后续访问时不必重新加载数据或重新初始化页面。
这就引入了 路由缓存 的概念。
路由缓存允许你在切换路由时保留组件的状态,以便在后续访问时能够快速恢复。这在一些场景下非常有用,比如用户在切换页面后仍然保留表单输入、滚动位置等。
然而,路由缓存也可能引发一些问题:
-
内存消耗: 缓存页面组件可能会导致内存占用增加,特别是如果应用有很多页面。
-
数据过时: 如果缓存的页面状态不及时更新,用户可能会看到过时的数据。
-
交互问题: 页面状态被保留可能导致一些交互问题,比如在某个路由上打开了一个弹出窗口,在切换路由后回来,弹出窗口可能仍然显示。
-
生命周期问题: 缓存的组件实例可能不会像重新创建的实例那样触发生命周期钩子,这可能会影响一些功能的正常运行。
更多详细内容,请微信搜索“前端爱好者
“, 戳我 查看 。
实现方法
<keep-alive>
组件
kee-alive
是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 , 也就是所谓的组件缓存。
keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
Props
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例
两个新的生命周期钩子
作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。只适用于keep-alive
例子
假设有两个页面组件:Home.vue 和 About.vue,希望在切换页面时保留 Home 组件的状态。可以这样使用 <keep-alive>
<template>
<div>
<router-link to="/home">Home</router-link>
<router-link to="/about">About</router-link>
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</template>
<keep-alive>
将会缓存 <router-view>
内的组件,也就是当前活动的路由组件。当从 Home 切换到 About 并再次回到 Home 时,Home 组件的状态将被保留,不会重新创建实例。
根据条件缓存页面
// 所有路径匹配到的视图组件都会被缓存!
<keep-alive>
<router-view></router-view>
</keep-alive>
// 只缓存组件name为aa或者bb的组件
<keep-alive include="aa,bb">
<component />
</keep-alive>
// 组件name为cc的组件不缓存
<keep-alive exclude="cc">
<component />
</keep-alive>
// 如果同时使用include,exclude,那么exclude优先于include, 下面的例子只缓存aa组件
<keep-alive include="aa,bb" exclude="bb">
<component />
</keep-alive>
// 如果缓存的组件超过了max设定的值3,那么将删除第一个缓存的组件
<keep-alive exclude="c" max="3">
<component />
</keep-alive>
缺点 :需要知道组件的 name,项目复杂的时候不是很好的选择
meta 字段
可以在路由配置中使用 meta 字段来控制是否缓存特定的页面。
优点:不需要例举出需要被缓存组件名称
示例一
//在 router 目录下的 index.js 文件里
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
import Layout from '@/layout'
export default new Router = [
{
path: '/admin',
component: Layout,
redirect: '/admin/user',
alwaysShow: true,
name: 'Admin',
meta: {
title: '系统管理',
icon: 'documentation'
},
children: [
{
path: 'user',
component: () => import('@/views/admin/user'),
name: 'User',
meta: {
title: '用户管理',
keepAlive: true // 需要缓存
}
},
{
path: 'user2',
component: () => import('@/views/admin/user2'),
name: 'User2',
meta: {
title: '用户管理2',
keepAlive: false // 不需要缓存,默认不缓存,可以不写
}
}
]
}
]
// App.vue
<template>
<div id="app">
<!-- <router-view/> -->
<!-- 可以被缓存的视图组件 -->
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<!-- 不可以被缓存的视图组件 -->
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
示例二
// router.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from './views/Home.vue';
import About from './views/About.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/home',
component: Home,
meta: { keepAlive: true } // 缓存 Home 组件
},
{
path: '/about',
component: About
// About 组件不会被缓存
}
];
const router = new VueRouter({
routes
});
export default router;
meta 字段被用于控制缓存行为。
keepAlive 是一个自定义的字段,你可以根据需要设置为 true 或 false 来决定是否缓存该路由对应的组件。
在 Home.vue 组件中,你可以使用 activated 和 deactivated 钩子来处理缓存状态
<template>
<div>
<h1>Home Page</h1>
<p>Count: {{ count }}</p>
</div>
</template>
<script>
export default {
name: 'Home',
data() {
return {
count: 0
};
},
activated() {
console.log('Home component activated');
},
deactivated() {
console.log('Home component deactivated');
},
methods: {
increment() {
this.count++;
}
}
};
</script>
Home 组件使用了 activated 和 deactivated 钩子来处理恢复状态和暂停状态的逻辑。
当用户切换到 /home 路由时,Home 组件会从缓存中恢复,并触发 activated 钩子。
当用户离开 /home 路由时,Home 组件会被缓存,并触发 deactivated 钩子。
示例三
const router = new VueRouter({
routes: [
{
path: '/example',
component: ExampleComponent,
meta: {
keepAlive: true // 设置缓存标识
}
},
// 其他路由配置...
]
})
然后,在路由切换时,通过监听 beforeRouteEnter 钩子函数来判断是否需要缓存该路由,例如:
beforeRouteEnter (to, from, next) {
if (to.meta.keepAlive) {
// 从缓存中获取组件实例
const cachedInstance = this.$router.getCachedInstance(to)
// 如果有缓存的实例,则直接使用
if (cachedInstance) {
next(vm => {
vm.$nextTick(() => {
next(false) // 不再进入组件的生命周期钩子
})
})
} else {
next()
}
} else {
next()
}
}
当访问带有 keepAlive 标识的路由时,会先检查是否有缓存的组件实例,如果有则直接使用,否则会正常创建和渲染新的实例。
拓展: 使用 router.meta
当然,也可以通过动态设置route.meta的keepAlive属性来实现其他需求,
首页是A页面
B页面跳转到A,A页面需要缓存
C页面跳转到A,A页面不需要被缓存
思路是在每个路由的beforeRouteLeave(to, from, next)钩子中设置to.meta.keepAlive:
A的路由
{
path: '/',
name: 'A',
component: A,
meta: {
keepAlive: true // 需要被缓存
}
}
export default {
data() {
return {};
},
methods: {},
beforeRouteLeave(to, from, next) {
// 设置下一个路由的 meta
to.meta.keepAlive = true; // B 跳转到 A 时,让 A 缓存,即不刷新
next();
}
};
export default {
data() {
return {};
},
methods: {},
beforeRouteLeave(to, from, next) {
// 设置下一个路由的 meta
to.meta.keepAlive = false; // C 跳转到 A 时让 A 不缓存,即刷新
next();
}
};
扩展:路由钩子函数
vue3 路由钩子函数
全局路由守卫
vue-router4.0中取消了next,可以不写;return true 或 Undefined 通过导航验证,return false 取消导航。
-
router.beforeEach((to,from)=>{}),next是可选参数,可不写,return false是取消导航,如果返回值为true或者是undefined就是通过验证
(路由跳转之前拦截) -
router.afterEach((to,from)=>{}) 路由跳转之后,语法糖: to.fullPath 可以直接获取当前的URL路径及传参
路由独享守卫
let routes = [
{
path:"/index",
name:"index",
component:index,
beforeEnter:(to,from) =>{
//to:当用户点击进入当前页面时,进行一些拦截设置
//from:当来自其他页面进入当前页面的时候,拦截提示用户
alert('路由独享守卫')
}
}
]
组件内路由守卫
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router';
onBeforeRouteUpdate((to,from)=>{//当前组件路由改变后触发
console.log(to);
})
onBeforeRouteLeave((to,from)=>{//离开当前的组件时触发
alert('')
})
新增的路由添加方法
// 添加一级路由
router.addRoute({
path:"/router",
name:"router",
component:()=>import('../views/router.vue')
})
// 添加二级路由
router.addRoute({ name: 'admin', path: '/admin', component: Admin })//1 父路由
router.addRoute('admin', { path: 'settings', component: AdminSettings })//1 子路由
// * 如果上面做法无效,就添加这行代码
router.replace(router.currentRoute.value.fullPath)//替换当前路由页面的路由
router.removeRoute('router'); // 删除路由;
Vue2 路由钩子函数
Vue2 路由钩子函数可以让开发者在路由导航过程中进行一些自定义逻辑处理。常用的路由钩子函数有以下三个:
-
beforeEach(to, from, next):在路由跳转之前调用,可以进行路由拦截、身份验证、权限校验等操作。
-
afterEach(to, from):在路由跳转完成后调用,可以进行页面标题设置、埋点统计等操作。
-
beforeRouteUpdate(to, from, next):在当前路由更新时调用,例如路由参数发生变化时。
这些函数都接收三个参数:
- to: 即将进入的目标路由对象
- from: 当前导航正要离开的路由
- next: 调用该方法后,才能进入下一个钩子或者路由
举个例子,在路由跳转前进行登录状态验证,如果未登录则跳转到登录页面:
router.beforeEach((to, from, next) => {
const isLoggedIn = checkLoginStatus(); // 检查登录状态
if (to.meta.requiresAuth && !isLoggedIn) { // 需要登录并且未登录
next('/login'); // 跳转到登录页面
} else {
next(); // 继续路由跳转
}
})
需要注意的是,next()只有在执行完所有自定义逻辑后才能调用,否则会阻止路由跳转。
参考文档
- https://blog.csdn.net/code_dream_wq/article/details/128713825
- https://blog.csdn.net/m0_71469120/article/details/132261103