:include 、 :exclude和abstract
include白名单,会缓存组件,exclude不会缓存,abstract看是否是抽象组件(这个到时候不说,因为害怕被追问抽象组件会不会被缓存),max,缓存上限。
(created)有cache和keys,分别存放vnode节点和对应的key值
cache中存的组件如果超过max,根据lru策略删除key[0]组件
render()会拿到组件的名字,匹配看它在不在include或exclude中,如果在include中,就缓存,如果在exclude中,就不缓存
render会把组件对象vnode,选择通过createElement或createComponent把vnode实例化,再用patch把vnode转化成真实dom
patch中vnode.componentInstance的值就是已经缓存的组件实例,那么会执行insert(parentElm, vnode.elm, refElm)逻辑,这样就直接把上一次的DOM插入到父元素中。
(首次加载被包裹组件时,vnode.componentInstance的值是undfined)
被缓存的组件实例会为其设置keepAlive= true
vnode.componentInstance和keepAlive同时为true时,不再进入$mount过程,那mounted之前的所有钩子函数(beforeCreate、created、mounted)都不再执行。
include定义缓存白名单,keep-alive会缓存
超过上限使用LRU的策略置换缓存数据
内存管理的一种页面置换算法,对于在内存中但又不用的数据块(内存块
叫做LRU,
//src/core/components/keep-alive.js
export default{
name:'keep-alive',
abstract: true, //判断当前组件虚拟dom是否渲染成真实dom的关键
props:{
include:patternTypes,缓存白名单,
exclude:patternTypes,缓存黑名单,
max:[String, Number]缓存的组件
},
created(){
this.cache=Object.create(null) //缓存虚拟dom
this.key=[] //缓存的虚拟dom
}
destroyed(){
for(const key in this.cache){
//删除所有的缓存
pruneCacheEntry(this.cache,key,this.keys)
}
},
mounted(){
//
}
}
created
初始化两个对象分别缓存VNode(虚拟dom和VNode对应的键的集合
destroyed
删除
actived(){}
一开始进来:
Comp A mounted
Comp A actived
点击A,切换成B:
Comp A deactivated
Comp B mounted
Comp B activated
点击又换成A:
Comp B deactivated
Comp A activated(没有执行mounted钩子)
keep-alive组件什么时候注册:
vue初始化时,会执行initGlobalAPI方法
initGlobalAPI中
会有extend(Vue.options.components, builtInComponents)
初始化vue的时候,已经把keepalive注册到全局了
keep-alive不会渲染任何实际节点 它是个抽象组件
vue初始化阶段 会执行initLifecycle方法,initLifecycle方法
会建立父组件链
当前object是abstract的话,是不会把它添加到父组件链中的,
会持续向上找,父子组件的关系中不会包含抽象组件
keep-alive。js中:
cache缓存vnode,keys保存vode对应的key值
render()返回个vnode
1.首先拿到默认插槽
const slot
然后通过 function initRender=>resolveSlots解析this.$slots
2.const vnode
getFirstComponentChild拿到第一个组件节点
3.const componentOptions
=》getComponentName 获取到组件名称
opts.Ctor.options 构造器对应的就是组件定义 .name拿到name
(include && (!name || !matcher(include, name)))
include不匹配到name 就不缓存 返回vnode(组件名在exclude中,
也是返回vnode)
const {cache:keys} 后面都是缓存vnode用的
=》matches(pattern: 可以是一个数组)=》 include/exclude可以是数组形式
//
在缓存中:
const {cache, keys}……
首先看看组件有没有key,如果没有就拼接出一个key(cid)
if(cache[key]) 如果命中缓存,做一个缓存的处理(pruneCacheEntry)
如果keys.length > this.max,要做一个 缓存清理
(keep-alive本质把vnode缓存到cache中
if(cached && (current || cached.tag !== current.tag))
当前渲染的节点 如果是我们要删除的这个cache 就不执行
cached.componentInstance.$destroy()
cache[key]=null 从缓存中清掉一个
if(cache[key]){
remove(keys, key) 首先把key删了
keys.push(key)
}
0:14:24 什么渲染的是要删除的 不会执行$destory(),但会把它从
cache中移除??
return vnode||(slot&&slot[0]) 没有vnode会返回slot第一个
接着看mounted()
pruneCache():
for( in )遍历 cache,拿到每一个节点,拿到每一个节点的名字
!filter(name) 如果名字不匹配,把它从节点中删除
0:15:41 filter matche
keep-alive 怎么渲染到dom上 以及它的生命周期??
fucntion createComponent()
首次渲染,会执行inithook
function createComponent(){根据vnode.componentInstance
&&vnode.keepAlive
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
在首次加载被包裹组建时,vnode.componentInstance的值是undfined,再次访问被包裹组件时,vnode.componentInstance的值就是已经缓存的组件实例,那么会执行insert(parentElm, vnode.elm, refElm)逻辑,这样就直接把上一次的DOM插入到父元素中。
被缓存的组件实例会为其设置keepAlive= true
vnode.componentInstance和keepAlive同时为true时,不再进入$mount过程,那mounted之前的所有钩子函数(beforeCreate、created、mounted)都不再执行。