一切的开始就是在KeepAlive组件的render方法中给缓存在cache里面的组件vnode加了一个属性
vnode.data.KeepAlive = true
接下来可以看看有data.keepAlive=true的vnode在非首次渲染是怎么触发钩子函数的 keepAlive里面包裹的一定是组件,vue给每一个组件都注册了几个vnodeHooks方法,用来执行组件的init(初始化),insert(插入)和destroy(销毁)的
- 首先看看data.keepAlive=true怎么影响init方法的
init: function init(vnode, hydrating) {
// data.keepAlive=true的vnode只会直接返回这个vnode,然后进行prepatch。不会执行mounted
if (
vnode.componentInstance &&
!vnode.componentInstance._isDestroyed &&
vnode.data.keepAlive
) {
// kept-alive components, treat as a patch
var mountedNode = vnode; // work around flow
componentVNodeHooks.prepatch(mountedNode, mountedNode);
} else {
// 如果有data.keepAlive=true这个属性,会走上面的if, 不会执行child.$mount方法
// 因为mounted的钩子方法只会在mounted方法里面调用,
// 所以如果data.keepAlive=true,是不会触发这个vnode对应的callHooks("mounted")的
var child = vnode.componentInstance = createComponentInstanceForVnode(
vnode,
activeInstance
);
child.$mount(hydrating ? vnode.elm : undefined, hydrating);
}
},
- 接着看看怎么影响destroyed方法。也看看怎么触发deactivated钩子的
destroy: function destroy(vnode) {
var componentInstance = vnode.componentInstance;
if (!componentInstance._isDestroyed) {
if (!vnode.data.keepAlive) {
componentInstance.$destroy();
} else {
// 如果有data.keepAlive=true这个属性不会像上面的if一样直接销毁
// 而是执行deactivateChildComponent方法,这个方法里面会调用deactivated钩子
deactivateChildComponent(componentInstance, true /* direct */);
}
}
}
function deactivateChildComponent(vm, direct) {
... 省略无关代码
if (!vm._inactive) {
// ... 省略无关代码
callHook(vm, 'deactivated');
}
}
- 最后怎么影响insert方法。也看看怎么触发activated钩子的
insert: function insert(vnode) {
var context = vnode.context;
var componentInstance = vnode.componentInstance;
// 如果是首次渲染,componentInstance._isMounted == false,会执行mounted方法
if (!componentInstance._isMounted) {
componentInstance._isMounted = true;
callHook(componentInstance, 'mounted');
}
// 否则,则直接按情况调用下面两个函数之一
if (vnode.data.keepAlive) {
if (context._isMounted) {
// 这里会activatedChildren.push(vm),将componentInstance推入一个数组里面先存起来
queueActivatedComponent(componentInstance);
} else {
// 这个方法会直接调用activated钩子,callHook(vm, 'activated');
activateChildComponent(componentInstance, true /* direct */);
}
}
},
function queueActivatedComponent(vm) {
vm._inactive = false;
// 将componentInstance推入一个数组里面先存起来
activatedChildren.push(vm);
}
// 在执行flushSchedulerQueue的时候
function flushSchedulerQueue() {
// ...省略无关代码
var activatedQueue = activatedChildren.slice();//上面的activatedChildren会赋值给activatedQueue
callActivatedHooks(activatedQueue); //数组中对象的activated依次执行
// ...省略无关代码
}
function callActivatedHooks(queue) {
for (var i = 0; i < queue.length; i++) {
queue[i]._inactive = true;
activateChildComponent(queue[i], true /* true */);//调用activated钩子
}
}
function activateChildComponent(vm, direct) {
// ...省略无关代码
if (vm._inactive || vm._inactive === null) {
//...省略无关代码
callHook(vm, 'activated');
}
}