vue 删除Keep-alive缓存
vue删除Keep-alive缓存keep-alive简单介绍:我们项目中为了用户有更好的体验/页面性能,大多数地方都会使用到keep-alive,这个是vue提供的组件,它会将它的子组件进行数据缓存/行为缓存。大致原理就是当离开当前组件时,组件并不会被销毁,而是保存的了内存中,下次再次访问的时候,不会重新创建新的组件实例,直接从内存中通过特定的key取出缓存的组件实例,进行渲染。问题:**最近我
·
vue删除Keep-alive缓存
keep-alive简单介绍:
- 我们项目中为了用户有更好的体验/页面性能,大多数地方都会使用到keep-alive,这个是vue提供的组件,它会将它的子组件进行数据缓存/行为缓存。
大致原理就是当离开当前组件时,组件并不会被销毁,而是保存在内存中,下次再次访问的时候,不会重新创建新的组件实例,直接从内存中通过特定的key取出缓存的组件实例,进行渲染。
问题:
**
- 最近我们项目提了一个用户体验的需求,希望同一个页面有些场景有缓存,但是有些场景不希望缓存。
**
需求背景:
- 当用户将标签页关闭之后,再打开时,之前的缓存还存在,用户希望当标签页存在,只是切换标签页时,希望有缓存,当用户点击关闭当前标签页时,希望将缓存清除
探究
- 当时我一开始看到这个需求,就开始找vue的文档,但是发现vue官方文档并没有提供这样的方法,所以就索性看keep-alive源码。下面直接贴出核心设置缓存的源码,一些关键的地方我都写上了注释
export default {
name: 'keep-alive',
abstract: true,
props: {
include: patternTypes,
exclude: patternTypes,
max: [String, Number]
},
created () {
// 初始化缓存列表,用于存储缓存的虚拟dom
this.cache = Object.create(null)
// 缓存的虚拟dom的key值列表
this.keys = []
},
destroyed () {
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys)
}
},
mounted () {
this.$watch('include', val => {
pruneCache(this, name => matches(val, name))
})
this.$watch('exclude', val => {
pruneCache(this, name => !matches(val, name))
})
},
render () {
const slot = this.$slots.default
// 获取keep-alive的第一个子节点(组件),这里要注意是第一个子节点,缓存存的也是这个子节点(组件)
const vnode: VNode = getFirstComponentChild(slot)
// 获取第一个子节点(组件)的配置信息
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
const name: ?string = getComponentName(componentOptions)
const { include, exclude } = this
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
const { cache, keys } = this
// 这里获取第一个子节点(组件)的key,
//如果没有key则利用ctro.cid和组件的name以及tag值拼接生成一个
const key: ?string = vnode.key == null
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode.key
// 判断是否存在缓存
if (cache[key]) {
// 如果已经存在,则使用缓存更新当前组件
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
// 同时更新Key
remove(keys, key)
keys.push(key)
} else {
// 如果不存在,则直接存入cache
// 这里关注cache 和keys
// 因为我们后续需要操作这两个变量进行缓存删除
cache[key] = vnode
keys.push(key)
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
}
通过上述源码,我们可以知道缓存都是存在了keep-alive组件内的cache对象内,以及同时保存了一个缓存组件的key值列表。我们只需要将cache内对应的组件缓存虚拟dom删除就可以达到缓存删除的目的了
实现:
/home/list.vue
//在list组件内的 beforeRouteLeave路由守卫里面操作
beforeRouteLeave(to,from,next){
// 拿到keep-alive的cache
// 此处我是因为多嵌套了一层 router-view
// 所以要向上取2层才能访问到keep-alive组件
const cache = this.$vnode.parent.parent.componentInstance.cache
// 拿到keep-alive的keys
const keys = this.$vnode.parent.parent.componentInstance.keys
// 获取keep-alive第一个子组件的key值
// 此处我是因为多嵌套了一层 router-view
// 所以要多向上取一次才是keep-alive的第一层子组件 router-view
const key = this.$vnode.parent.key == null
? this.$vnode.parent.componentOptions.Ctor.cid + (this.$vnode.parent.componentOptions.tag ? `::${this.$vnode.parent.componentOptions.tag}` : '')
: this.$vnode.parent.key;
// 我们的业务(判断当前所有打开的标签页是否有当前页面)
const flag = this.$store.state.tagsView.visitedViews.find(tag => tag.name === "examManagement")
if(!flag){
if(keys.length) {
let index = keys.indexOf(key)
// 删除存在keep-alive keys列表内的组件key
if(index > -1) keys.splice(index,1)
}
// 删除当前组件的缓存
delete cache[key]
this.$destroy(); // 缓存删除了,顺便也让当前组件销毁
}
next()
},
到此就实现了Keep-alive特定场景缓存删除功能
需要注意的点就是:需要访问到keep-alive组件,因为缓存是存在keep-alive组件内的cache对象内,还有就是keep-alive缓存的是第一层子组件。所以实现时要注意组件嵌套关系。
更多推荐
已为社区贡献6条内容
所有评论(0)