在某一些特定场景下,跳转页面后再返回我们不希望销毁组件,而是希望页面缓存下来,保存跳转前的状态,这时候就可以用到keep-alive组件。
官方介绍
这个地方请注意有一个坑点,include 和 exclude 包含的name 是组件的name不是router name.
使用场景
如果未使用keep-alive组件,在路由切换会对界面进行销毁,在某些业务场景下会使用户体验不是很友好。
- 主页面跳转详情页再次从详情页跳转回主页面的时候需要主页面保留搜索条件以及数据。
- 后台系统常见的跳转后添加顶部标签,标签之间切换期望保留数据。
弊端
- 不能保证系统的数据时效性。
- keep-alive 的本质是保持页面不销毁,这样会增加内存的占用。
keep-alive的生命周期
- 初次进入时:created > mounted > activated;退出后触发 deactivated
- 再次进入:会触发 activated;事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中
项目实践
- 更改HTML模板。
<keep-alive :include="cachViews">
<router-view :key="key" class="container" />
</keep-alive>
- 在路由中设置一个keepAlive
{
meta: {
keepAlive: true
}
path: 'home',
component: lazyLoad('home')
}
- 监听路由变化添加到全局状态机中
watch: {
$route() {
if (this.$route.meta.keepAlive) {
this.addCachViews();
}
},
}
- 添加一个全局的beforeRouteLeave钩子用于销毁缓存页面
Vue.mixin({
beforeRouteLeave(to, from, next) {
if (!from.meta.keepAlive) {
this.$destroy(true);
}
next();
},
})
为什么要这样来销毁缓存页面而不使用exclude亦或是使用两个router-view。
在一个嵌套三层的路由结构下你会发现缓存可能失效了,原因是因为父级Blank不存在于include中,你需要把父级加入到include。 但是我们只希望index被缓存,details不被缓存,但是父级有了缓存导致就算details不在include中也会被缓存。
这时候上面的钩子就起到作用了,退出页面的时候手动销毁details页面
{
path: '/Layout',
name: 'Layout',
component: Layout, // 整个后台项目的框架
children: [
{
path: 'Blank',
name: 'Blank',
component: Blank, // 空白页面
children: [{
keepAlive: true,
path: 'index',
name: 'index',
component: index, // 主页
}, {
path: 'details',
name: 'details',
component: details, // 详情页
}]
}
]
}
同时网上很多的解决方案都是用router-view如下。
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
同样以上面三层嵌套为例。这样写你会发现进入到index进入details再进index这个时候index 的缓存被刷新了。
总结:
1、多级嵌套导致缓存不生效,这个时候可能是因为你没有把父级的空页面加入到include中。
2.、include需要的name是组件的name,不是router name。
3、 多级嵌套兄弟页面A需要缓存,B不需要缓存。同时只把A页面添加到了include中但是B页面也缓存了,那么应该是因为他们的父级加入到了include中,需要手动销毁B页面。