keep-alive是什么"
这个组件的功能只有一个那就是缓存组件,可以让其包裹的组件不销毁,起到一个缓存的作用。
接受可选的三个参数
max 缓存的最大组件数量,支持数字和字符串
include 需要缓存的数据,支持字符串,数组,正则
exclude 不需要缓存的数据,支持字符串,数组,正则
keep-alive 原理
获取 `keep-alive` 包裹着的第一个子组件对象及其组件名; 如果 keep-alive 存在多个子元素,`keep-alive` 要求同时只有一个子元素被渲染。所以在开头会获取插槽内的子元素,调用 `getFirstComponentChild` 获取到第一个子元素的 `VNode`。
根据设定的黑白名单(如果有)进行条件匹配,决定是否缓存。不匹配,直接返回组件实例(`VNode`),否则开启缓存策略。
根据组件ID和tag生成缓存Key,并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值并更新该key在`this.keys`中的位置(更新key的位置是实现`LRU`置换策略的关键)。
如果不存在,则在`this.cache`对象中存储该组件实例并保存key值,之后检查缓存的实例数量是否超过max设置值,超过则根据`LRU`置换策略删除最近最久未使用的实例(即是下标为0的那个key)。最后将该组件实例的`keepAlive`属性值设置为`true`
keep-alive 在每个生命周期都做了什么
1. `created`:初始化一个`cache、keys`,前者用来存缓存组件的虚拟dom集合,后者用来存缓存组件的key集合
2. `mounted`:实时监听`include、exclude`这两个的变化,并执行相应操作
3. `destroyed`:删除掉所有缓存相关的东西
var KeepAlive = {
name: 'keep-alive',
abstract: true,
props: {
include: patternTypes,
exclude: patternTypes,
max: [String, Number]
},
created: function created () {
this.cache = Object.create(null);
this.keys = [];
},
destroyed: function destroyed () {
for (var key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys);
}
},
mounted: function mounted () {
var this$1 = this;
this.$watch('include', function (val) {
pruneCache(this$1, function (name) { return matches(val, name); });
});
this.$watch('exclude', function (val) {
pruneCache(this$1, function (name) { return !matches(val, name); });
});
},
render: function render () {
var slot = this.$slots.default;
var vnode = getFirstComponentChild(slot);
var componentOptions = vnode && vnode.componentOptions;
if (componentOptions) {
var name = getComponentName(componentOptions);
var ref = this;
var include = ref.include;
var exclude = ref.exclude;
if (
(include && (!name || !matches(include, name))) ||
(exclude && name && matches(exclude, name))
) {
return vnode
}
var ref$1 = this;
var cache = ref$1.cache;
var keys = ref$1.keys;
var key = vnode.key == null
? componentOptions.Ctor.cid + (componentOptions.tag ? ("::" + (componentOptions.tag)) : '')
: vnode.key;
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance;
remove(keys, key);
keys.push(key);
} else {
cache[key] = vnode;
keys.push(key);
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode);
}
}
vnode.data.keepAlive = true;
}
return vnode || (slot && slot[0])
}
};