浅谈Vue页面级缓存解决方案feb-alive(上)

2020-06-14 06:24:38易采站长站整理

abstract: true,

props: {
include: patternTypes,
exclude: patternTypes,
max: [String, Number] },

created () {
this.cache = Object.create(null)
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要求同时只有一个子元素被渲染,如果你在其中有 v-for 则不会工作。
const vnode: VNode = getFirstComponentChild(slot)
// 判断是否存在组件选项,也就是说只对组件有效,对于普通的元素则直接返回对应的vnode
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// 检测include和exclude
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则使用,否则通过cid+tag生成一个key
const key: ?string = vnode.key == null
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode.key
// 判断是否存在缓存
if (cache[key]) {
// 直接复用组件实例,并更新key的位置
vnode.componentInstance = cache[key].componentInstance
remove(keys, key)
keys.push(key)
} else {
// 此处存储的vnode还没有实例,在之后的流程中通过在createComponent中会生成实例
cache[key] = vnode
keys.push(key)
// 当缓存数量大于阈值时,删除最早的key
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
// 设置keepAlive属性,createComponent中会判断是否已经生成组件实例,如果是且keepAlive为true则会触发actived钩子。
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
}

keep-alive是一个抽象组件,组件实例中维护了一份cache,也就是以下代码部分


created () {
// 存储组件缓存
this.cache = Object.create(null)
this.keys = []}

由于路由切换并不会销毁keep-alive组件,所以缓存是一直存在的(嵌套路由中,子路由外层的keep-alive情况会不一样,后续会提到)