官方解释:
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 相似, 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。当组件在 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。主要用于保留组件状态或避免重新渲染。keep-alive 是 Vue 的内置组件,在组件切换过程中将状态保留在内存中,等再次访问的时候,还保持着离开之前的所有状态,而不是重新初始化。也就是所谓的组件缓存。我们知道,使用路由vue-router切换组件的时候是不保存状态的,它进行router.push()或router.push()或router.replace()的时候,旧组件会被销毁,新组件会被新建,然后走一遍完整的生命周期。所以缓存经常与router-view一起出现:









被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated:1. activated:在 keep-alive 组件激活时调用
2. deactivated:在 keep-alive 组件停用时调用注意: 只有组件被 keep-alive 包裹时,这两个生命周期函数才会被调用。这两个钩子在服务器端渲染期间不被调用。应用场景:应用场景:官网有一个多标签界面的例子,介绍的还是蛮详细的。官网我们在实际开发项目中会有一些需求,比如跳转到详情页面时,需要保持列表页的滚动条的位置,返回的时候依然在这个位置,这样可以提高用户体验,这个时候就可以使用缓存组件 keep-alive 来解决。设置了 keep-alive 缓存的组件,会多出两个生命周期钩子:

首次进入组件时:beforeRouteEnter > beforeCreate > created > mounted > activated > ... ... > beforeRouteLeave > deactivated

再次进入组件时:beforeRouteEnter > activated > ... ... > beforeRouteLeave > deactivated
首次进入组件时:beforeRouteEnter > beforeCreate > created > mounted > activated > ... ... > beforeRouteLeave > deactivated再次进入组件时:beforeRouteEnter > activated > ... ... > beforeRouteLeave > deactivated可以看到,缓存的组件中 activated 钩子函数每次都会触发,所以可以通过这个钩子判断,当前组件时需要使用缓存的数据还是重新调用接口加载数据。如果未使用keep-alive 组件,则在页面回退时会重新渲染页面,首次进入组件的一系列生命周期也会一一被触发。离开组件时,使用了 keep-alive 不会调用 beforeDestroy 和 destroyed 钩子,因为组件没被销毁,被缓存起来了。所以 deactivated 这个钩子可以看作是 beforeDestroy 和 destroyed 的代替,缓存组件销毁的时候要做的一些操作可以放在这个里面。需求案例需求案例最近项目中碰到需要缓存的场景,主要还是列表页到详情页的跳转,但列表页存在多级关系,具体需求如下:初次进入此页面,默认展示左侧的树形结构菜单,点击某一菜单,右侧加载该菜单相应的数据列表,由列表进入详情内页,然后再返回该页面,希望该页面保留了用户之前选择的树形菜单及数据列表。若从其他页面进入此页面,则不需要缓存。案例实践案例实践案例实践思路:结合 router 中设置 meta 信息,缓存列表页。
1. 设置路由的 meta 信息
const List = () => import(/* webpackChunkName: "list" */ '../pages/List.vue')
const Detail = () => import(/* webpackChunkName: "detail" */ '../pages/Detail.vue')
{

path: 'list',

name: 'list',

component: List,

meta: {

title: '列表',

keepAlive: true, //需要缓存

isKeep: false

}
},
{

path: 'dist',

name: 'detail',

component: Detail
}

const List = () => import(/* webpackChunkName: "list" */ '../pages/List.vue')
const Detail = () => import(/* webpackChunkName: "detail" */ '../pages/Detail.vue')
{

path: 'list',

name: 'list',

component: List,

meta: {

title: '列表',

keepAlive: true, //需要缓存

isKeep: false

}
},
{

path: 'dist',

name: 'detail',

component: Detail
}
2. 修改渲染匹配视图组件 router-view(一般是 app.vue 文件,根据实际需求会不一样)





























也可以使用 keep-alive 组件的 include/exclude 属性,include 表示要缓存的组件名(定义时的 name 属性),而 exclude 相反,匹配到的组件不会被缓存。

















3. 在需要缓存的页面中,通过导航守卫 beforeRouteEnter 和 activated 钩子判断使用缓存还是重新渲染
beforeRouteEnter (to, from, next) {

// 只在详情返回时做缓存

if (from.name === 'detail') {

to.meta.isKeep = true

} else {

to.meta.isKeep = false

}

next()
},
activated () {

if(this.$route.meta.isKeep) {

// 详情返回,取缓存数据

} else {

// 重新渲染,在这里调用加载请求

}
}

beforeRouteEnter (to, from, next) {

// 只在详情返回时做缓存

if (from.name === 'detail') {

to.meta.isKeep = true

} else {

to.meta.isKeep = false

}

next()
},
activated () {

if(this.$route.meta.isKeep) {

// 详情返回,取缓存数据

} else {

// 重新渲染,在这里调用加载请求

}
}
此处 beforeRouteEnter 钩子也可以使用 watch 属性监听路由的变化:
watch: {

$route(to, from) {

//通过to/from.path判断是否是需要缓存的路径然后添加逻辑

}
}

watch: {

$route(to, from) {

//通过to/from.path判断是否是需要缓存的路径然后添加逻辑

}
}
问题:从详情返回列表时正常,但当用户在详情页按 F5 刷新之后,再返回列表就不能保留离开之前的状态了,因为这时页面重载了。解决办法:在离开当前之前,将信息储存在 localStorage 中,当详情数据刷新后,手动触发加载请求。