一、概念:内置的抽象组件,自身不会渲染Dom元素,也不会出现在父组件链中。【abstract:true --- 判断当前组件虚拟dom是否渲染成真实dom的关键】。
二、作用:缓存不活动的组件实例。
三、场景: 列表页面选择筛选条件过滤一份数据列表, 再进入详情页面,再返回该列表页面、我们希望:表页面可以保留用户的筛选(或选中)状态。
四、用法:
1、在动态组件中的应用
2、在vue-router中的应用
include: 定义缓存白名单,keep-alive会缓存命中的组件
exclude: 定义缓存黑名单,被命中的组件将不会被缓存
max: 义缓存组件上限,超出上限使用LRU的策略置换缓存数据【内存管理的一种页面置换算法,对于在内存中但又不用的数据块(内存块),操作系统会根据哪些数据属于LRU而将其移出内存而腾出空间来加载另外的数据】
四、源码
ps、定义了三个钩子函数
created: 初始化两个对象分别缓存VNode(虚拟DOM)和VNode对应的key键集合
destroyed: 删除this.cache中缓存的VNode实例 (不是简单地将this.cache置为null,而是遍历调用pruneCacheEntry函数删除。)
mounted: 对include和exclude参数进行监听,然后实时地更新(删除)this.cache对象数据。
******this.cache 缓存已经创建过的 vnode
******直接实现了 render 函数,而不是我们常规模板的方式。
render方法:
第一步:获取keep-alive包裹着的第一个子组件对象及其组件名;
第二步:根据设定的黑白名单(如果有)进行条件匹配,决定是否缓存。不匹配,直接返回组件实例(VNode),否则执行
第三步;
第三步:根据组件ID和tag生成缓存Key,并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值并更新该key在this.keys中的位置(更新key的位置是实现LRU置换策略的关键),否则执行第四步;
第四步:在this.cache对象中存储该组件实例并保存key值,之后检查缓存的实例数量是否超过max设置值,超过则根据LRU置换策略删除最近最久未使用的实例(即是下标为0的那个key);
第五步:最后并且很重要,将该组件实例的keepAlive属性值设置为true。
五、渲染
Vue的渲染是从图中render阶段开始的
但keep-alive的渲染是在patch阶段(构建组件树(虚拟DOM树),并将VNode转换成真正DOM节点的过程)
六、keep-alive包裹的组件是如何使用缓存的?【在patch阶段,会执行createComponent函数】
1、在首次加载被包裹组建时,由keep-alive.js中的render函数可知,vnode.componentInstance的值是undfined,keepAlive的值是true,因为keep-alive组件作为父组件,它的render函数会先于被包裹组件执行;那么只执行到i(vnode,false),后面的逻辑不执行;
2、再次访问被包裹组件时,vnode.componentInstance的值就是已经缓存的组件实例,那么会执行insert(parentElm, vnode.elm, refElm)逻辑,这样就直接把上一次的DOM插入到父元素中。