跳到主要内容

认识

2023年06月10日
柏拉文
越努力,越幸运

一、认识


Vue.js 3.0 中, KeepAlive 可以避免一个组件被频繁地销毁和重建。KeepAlive 本质是缓存管理, 再加上特殊的挂载和卸载逻辑。KeepAlive 实现逻辑如下所示:

const KeepAlive = {
props: {
max: Number,
include: RegExp,
exclude: RegExp
},
setup(props,setupContext){
const { slots } = setupContext;
……,
return ()=>{
let rawVNode = slots.default();
const cache = new Map(); // key: rawVNode.type, value: rawVNode
……,
return rawVNode 或者 cache.get(rawVNode.type);
}
}
}

由上所示, KeepAlive 组件本身不会渲染额外内容, KeepAlive 的工作是对在 组件VNode 对象上添加一些标记属性,以便渲染器能够依据这些标记属性执行特定的逻辑。 KeepAlive 的渲染函数最终只返回需要被 KeepAlive 的组件

二、标记细节


KeepAlive 的工作是对在 组件VNode 对象上添加一些标记属性,以便渲染器能够依据这些标记属性执行特定的逻辑。标记属性 如下所示

2.1 keptAlive

keptAlive 标记组件是否已经被缓存。如果 keptAlivetrue 时, 组件需要重新渲染的时候, 渲染器并不会重新挂载它, 而是将它激活。

const processComponent = (n1, n2, container, anchor) => {
if (n1 == null) {
if (n2.keptAlive) {
n2.keepAliveInstance._activate(n2, container, anchor);
} else {
mountComponent(n2, container, anchor);
}
} else {
updateComponent(n1, n2, container, anchor);
}
};

2.2 keepAliveCtx

keepAliveCtxKeepAlive 组件实例独有属性。存入move函数、createElement 函数等。基本逻辑如下所示:

function mountComponent(vnode, container, anchor){
……,
/**
* @description: 组件实例
*/
const instance = {
state,
attrs,
slots,
mounted: [],
subTree: null,
isMounted: false,
keepAliveCtx: null,
props: shallowReactive(props)
};
const isKeepAlive = vnode.type.__isKeepAlive;

if (isKeepAlive) {
instance.keepAliveCtx = {
move(vnode, container, anchor) {
insert(vnode.component.subTree.el, container, anchor);
},
createElement
};
}
……
}

2.3 shouldKeepAlive

shouldKeepAlive 属性会添加到组件的 VNode 对象上, 这样当渲染器卸载组件时, 可以通过检查该属性得知该组件需要被 KeepAlive,因此组件不会真的被卸载,而是调用 _deActivate 完成卸载。

const unmount = vnode => {
if (vnode.type === Fragment) {
vnode.children.forEach(c => unmount(c));
return;
} else if (typeof vnode.type === 'object') {
if (vnode.shouldKeepAlive) {
vnode.keepAliveInstance._deActivate(vnode);
} else {
unmount(vnode.component.subTree);
}
return;
}

const parent = vnode.el.parentNode;
if (parent) {
parent.removeChild(vnode.el);
}
}

2.4 keepAliveInstance

keepAliveInstance 组件 VNode 对象会持有 KeepAlive 组件的实例, 在 unmount 函数中会通过 keepAliveInstance 来访问 _deActivate 函数。

三、激失细节


3.1 激活

instance._activate = (vnode, container, anchor) => {
move(vnode, container, anchor);
};

激活 的本质是将组件所渲染的内容移动到隐藏容器中

3.2 失活

instance._deActive = vnode => {
move(vnode, storageContainer);
};

失活 的本质是将组件所渲染的内容从隐藏容器中搬运回原来的容器

四、属性细节


4.1 include

include 用于显式地配置应该被缓存的组件

4.2 exclude

exclude 用于显式地配置不应该被缓存的组件

五、缓存细节


Vue.js 3.0 使用 LRU 缓存淘汰策略管理组件缓存。新缓存的组件 或者 被访问的缓存组件 放到第一项, 当缓存超过 max 阈值时, 删除最后一项(即最长时间没被访问)的组件。