持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情
关于keep-alive的具体用法已在上文做了详解,想要深入了解其具体实现原理,可以查看vue源码地址。本文将逐步分析源码并做一些总结。
组件基础
首先将组件名设置为keep-alive,接收include,exclude,max三个参数,定义abstract属性,该属性决定了keep-alive会不会被渲染到页面上
接着可以看到keep-alive在它生命周期上定义的三个钩子函数:created,mounted,destroyed
created方法很简单,就是初始化了cache(用来存放缓存组件的虚拟dom集合)和keys(用来存放缓存组件的key的集合)
mounted方法主要是实时对include和excluede这两个参数进行监听,并实时更新到cache数组中。pruneCache函数的核心也主要是去调用prueCacheEntry,下文讲到。
destroyed方法则是删除cache缓存的实例。核心是调用prueCacheEntry进行删除操作。
重点看prueCacheEntry方法:可以看到,该方法遍历集合去执行所有缓存组件的destory钩子函数,并将cache对应的key设为null,并删除keys中对应的元素。
render函数
keep-alive渲染
- keep-alive它不会生成真正的DOM节点,这是怎么做到的?
因为Vue初始化生命周期时,源码中为组件实例建立父子关系的时候会根据abstract属性决定是否忽略某个组件。而我们从上文组件基础中可以看到在keep-alive中,设置了abstract: true,那Vue就会跳过该组件实例。
因此在最后构建的组件树中就不会包含keep-alive组件,那么由组件树渲染成的DOM树自然也不会有keep-alive相关的节点了。
- keep-alive包裹的组件是如何使用缓存的?
在首次加载被包裹组件时,由上文组件基础的render函数可知,vnode.componentInstance的值是undefined,且keepAlive的值是true,因为keep-alive组件作为父组件,它的render函数会先于被包裹组件执行;那么就只执行到i(vnode, false /* hydrating */),后面的逻辑不再执行;
而当再次访问被包裹组件时,vnode.componentInstance的值就是已经缓存的组件实例,那么会执行insert(parentElm, vnode.elm, refElm)方法,就可以直接把上一次的DOM插入到了父元素中。从而实现缓存。