vue keepalive的使用与原理
场景:A->B不需要缓存,C->B需要缓存
网上很多解决方案,大致思路是在路由里面添加keepAlive状态值,app.vue里面根据这个状态值判断是否需要添加keepAlive组件;在离开A页面进入B页面的时候,将这个状态值置为false,在离开C回到B页面时将状态值置为true
//在router里面添加mata
{
path: '/b',
name: 'B',
component: B,
meta:{
keepAlive:true
}
}
//在app.vue中
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
//在A页面中
beforeRouteLeave(to, from, next) {
to.meta.keepAlive = false;
next();
}
//在C页面中
beforeRouteLeave(to, from, next) {
to.meta.keepAlive = true;
next();
}
第一次A>B>C,之后再返回B的话,不会被缓存。
从B到A,之后到B,B没被缓存,表现正常,之后点击C,这个时候从C返回,得到的是一开始B的缓存
最终解决方案:利用keepalive组件的include参数,配合vuex状态管理,动态添加需要被缓存的页面。具体做法是在vuex中定义一个数组用来存放需要被缓存页面的name值,然后在路由守卫beforeEach函数中监听要跳转的页面,并把需要缓存页面的name值存入vuex的数组中,当B->A时,删除存放于vuex数组中的name。
大致原理:只要是B页面(需要缓存的页面,都缓存),在返回到A时清除对应缓存name
源码
vue版本:2.6.11
源码位置:src->core->components->keep-alive.js
创建阶段:created里面会创建一个cache对象,用来保存vnode节点
销毁阶段:destroyed 钩子则会调用pruneCacheEntry方法清除cache缓存中的所有组件实例
渲染阶段:
1、获取当前组件的name值
2、将name通过include与exclude属性进行匹配,匹配不成功(说明不需要缓存)则直接返回vnode
3、若有缓存则取缓存中的组件实例,若没有则缓存该组件
4、缓存超过最大值会删掉第一个缓存
如果中途有对include和exclude的修改,那么watch会监听到改变,然后对应更新cache中的值。
所以上面的问题好解释了,在路由的mate里面加状态值实际上并没有像include这样被watch监听到,所以会出现问题。