首先说明文中大部分思想来自这里:传送门,这篇文章只是摘要性整理。
keep-alive组件缓存基于VNode节点而不是直接存储DOM结构。它将满足条件(include与exclude)的组件在cache对象中缓存起来,在需要重新渲染的时候再将vnode节点从cache对象中取出并渲染。
1、DOM虚拟化及销毁
created钩子会创建一个cache对象,用来作为缓存容器,保存vnode节点。
created () {
/* 缓存对象 */
this.cache = Object.create(null)
},
destroyed钩子则在组件被销毁的时候清除cache缓存中的所有组件实例。
/* destroyed钩子中销毁所有cache中的组件实例 */
destroyed () {
for (const key in this.cache) {
pruneCacheEntry(this.cache[key])
}
},
2、组件渲染过程
render函数
render () {
/* 得到slot插槽中的第一个组件 */
const vnode: VNode = getFirstComponentChild(this.$slots.default)
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
/* 获取组件名称,优先获取组件的name字段,否则是组件的tag */
const name: ?string = getComponentName(componentOptions)
/* name不在inlcude中或者在exlude中则直接返回vnode(没有取缓存) */
if (name && (
(this.include && !matches(this.include, name)) ||
(this.exclude && matches(this.exclude, name))
)) {
return vnode
}
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
/* 如果已经做过缓存了则直接从缓存中获取组件实例给vnode,还未缓存过则进行缓存 */
if (this.cache[key]) {
vnode.componentInstance = this.cache[key].componentInstance
} else {
this.cache[key] = vnode
}
/* keepAlive标记位 */
vnode.data.keepAlive = true
}
return vnode
}
this.cache存储已缓存组件
- 获取组件name属性,否则使用tag
- 将name与include和exclude属性进行匹配,匹配不成功则不进行任何操作直接返回vnode
- 根据key在this.cache中查找,如果存在则说明之前已经缓存过了,直接将缓存的vnode的componentInstance(组件实例)覆盖到目前的vnode上面。否则将vnode存储在cache中。
if (this.cache[key]) {
vnode.componentInstance = this.cache[key].componentInstance
} else {
this.cache[key] = vnode
}
3、修改cache中缓存数据
watch
用watch来监听include与exclude这两个属性的改变,在改变的时候修改cache缓存中的缓存数据。
watch: {
/* 监视include以及exclude,在被修改的时候对cache进行修正 */
include (val: string | RegExp) {
pruneCache(this.cache, this._vnode, name => matches(val, name))
},
exclude (val: string | RegExp) {
pruneCache(this.cache, this._vnode, name => !matches(val, name))
}
},