一、场景描述
项目中常见的一个场景是:
主页->列表页->详情页层层深入,详情页->列表页->主页层层返回。
为了提升用户体验和性能,我们希望可以动态缓存列表页面:
从详情页->列表页时,用缓存中的列表页,不用重新请求数据。
从列表页->主页时,注销掉列表页,再进入列表页时,获取最新的数据。
现在,我们用keep-alive来实现这个功能。
二、keep-alive知识回顾
官方文档这样介绍keep-alive
keep-alive
Props:
include
- 字符串或正则表达式。只有名称匹配的组件会被缓存。exclude
- 字符串或正则表达式。任何名称匹配的组件都不会被缓存。max
- 数字。最多可以缓存多少组件实例。
用法:
<keep-alive>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和<transition>
相似,<keep-alive>
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。当组件在
<keep-alive>
内被切换,它的activated
和deactivated
这两个生命周期钩子函数将会被对应执行。
三、功能实现
01
定义router
用keepAlive表示路由对应的组件是否需要缓存、deepth表示当前路由的层级。
代码:
export default new Router({
routes: [
{
path: '/',
name: 'index',
meta: {
deepth: 0
},
component: Index
},
{
path: '/list',
name: 'list',
meta: {
deepth: 1, // 当前路由层级
keepAlive: true // 是否需要缓存
},
component: List
},
{
path: '/detail',
name: 'detail',
meta: {
deepth: 2
},
component: Detail
}
]
})
02
按需缓存router-view
keep-alive组件的include属性表示只有name匹配的组件会被缓存。我们可以动态修改include属性的值来实现按需缓存。
<keep-alive :include="includeArr.length==0?' ':includeArr.join(',')">
<router-view ></router-view>
</keep-alive>
如果要to(进入)的页面是需要keepAlive缓存的,把to.name push进includeArr数组。
如果要form(离开)的页面是keepAlive缓存的,再根据deepth来判断是前进还是后退。如果是后退,删除掉includeArr数组里from.name,也就是注销掉缓存组件。
$route (to, from) {
// 如果 要 to(进入) 的页面是需要 keepAlive 缓存的,把 name push 进 includeArr数组
if (to.meta.keepAlive) {
!this.includeArr.includes(to.name) && this.includeArr.push(to.name)
}
// 如果 要 form(离开) 的页面是 keepAlive缓存的,再根据 deepth 来判断是前进还是后退,如果是后退,需要注销缓存的组件。
if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
var index = this.includeArr.indexOf(from.name)
index !== -1 && this.includeArr.splice(index, 1)
}
}
注意:keep-alive组件的include属性匹配的是组件的name值,includeArr数组存的是router的name值,所以,我们要把router的name属性设置成router对应组件的name一样的。
完整代码:
<template>
<div id="app">
<router-link :to="{name: 'index'}">index</router-link>
<router-link :to="{name: 'list'}">list</router-link>
<router-link :to="{name: 'detail'}">detail</router-link>
<keep-alive :include="includeArr.length==0?' ':includeArr.join(',')">
<router-view ></router-view>
</keep-alive>
</div>
</template>
<script>
export default {
name: 'App',
data: () => {
return {
includeArr: []
}
},
watch: {
$route (to, from) {
// 如果 要 to(进入) 的页面是需要 keepAlive 缓存的,把 name push 进 include数组
if (to.meta.keepAlive) {
!this.includeArr.includes(to.name) && this.includeArr.push(to.name)
}
// 如果 要 form(离开) 的页面是 keepAlive缓存的,再根据 deepth 来判断是前进还是后退,如果是后退,需要清掉缓存的组件。
if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
var index = this.includeArr.indexOf(from.name)
index !== -1 && this.includeArr.splice(index, 1)
}
}
}
}
</script>
<style>
</style>
这样就实现了按需动态keep-alive。
四、效果
打开vue-devtool里注意观察list组件的变化(灰色为缓存状态的组件)。
1.从首页进入列表页:list组件被缓存,执行以下生命周期函数;
beforeCreate
created
beforeMount
mounted
activated
2.从列表页进入详情页:list组件并没有被注销,执行以下生命周期函数;
deactivated
3.从详情页再返回列表页:没有重新渲染list组件,用的是缓存中的list组件,执行以下生命周期函数;
activated
4.从列表页返回首页:缓存的list组件被注销,执行以下生命周期函数;
deactivated
beforeDestroy
destroyed
5.再次从首页进入列表页:重新渲染list组件,list组件执行以下生命周期函数;
beforeCreate
created
beforeMount
mounted
activated
如果您有关于本文的任何问题,欢迎沟通!感谢阅读~
扫描二维码
关注更多精彩