被
keep-alive
缓存的组件会多两个生命周期activated
、deactivated
,缓存后的组件经常会用activated
这个生命周期,那么这两个生命周期和vue的其他生命周期怎么排序执行的呢?
我们知道VUE的其他的生命周期是这样的:
activated 这个生命周期呢?
我们可以从源码src/core/vdom/create-component.js
看到:
insert (vnode: MountedComponentVNode) {
const { context, componentInstance } = vnode
if (!componentInstance._isMounted) {
componentInstance._isMounted = true
callHook(componentInstance, 'mounted')
}
if (vnode.data.keepAlive) {
if (context._isMounted) {
// vue-router#1212
// During updates, a kept-alive component's child components may
// change, so directly walking the tree here may call activated hooks
// on incorrect children. Instead we push them into a queue which will
// be processed after the whole patch process ended.
queueActivatedComponent(componentInstance)
} else {
activateChildComponent(componentInstance, true /* direct */)
}
}
}
从上面源码可以看到,组件的mounted
挂载后,回去判断当前组件是否vnode.data.keepAlive
,如果context._isMounted
是true那么有可能keep-alive
组件的子组件也许会改变,因此直接在此处行走树可能会在不正确的子组件上调用已激活的钩子。相反我们把它们推入队列,整个patch
过程结束后将对其进行处理。
src/core/observer/scheduler.js
/**
* Queue a kept-alive component that was activated during the patch.
* The queue will be processed after the entire tree has been patched.
*/
export function queueActivatedComponent (vm: Component) {
// setting _inactive to false here so that a render function can
// rely on checking whether it's in an inactive tree (e.g. router-view)
vm._inactive = false
activatedChildren.push(vm)
}
...
...
/**
* Push a watcher into the watcher queue.
* Jobs with duplicate IDs will be skipped unless it's
* pushed when the queue is being flushed.
*/
export function queueWatcher (watcher: Watcher) {
const id = watcher.id
if (has[id] == null) {
has[id] = true
if (!flushing) {
queue.push(watcher)
} else {
// if already flushing, splice the watcher based on its id
// if already past its id, it will be run next immediately.
let i = queue.length - 1
while (i > index && queue[i].id > watcher.id) {
i--
}
queue.splice(i + 1, 0, watcher)
}
// queue the flush
if (!waiting) {
waiting = true
if (process.env.NODE_ENV !== 'production' && !config.async) {
flushSchedulerQueue()
return
}
nextTick(flushSchedulerQueue)
}
}
}
上面代码是做队列处理。
src/core/instance/lifecycle.js
export function activateChildComponent (vm: Component, direct?: boolean) {
if (direct) {
vm._directInactive = false
if (isInInactiveTree(vm)) {
return
}
} else if (vm._directInactive) {
return
}
if (vm._inactive || vm._inactive === null) {
vm._inactive = false
for (let i = 0; i < vm.$children.length; i++) {
activateChildComponent(vm.$children[i])
}
callHook(vm, 'activated')
}
}
上面是发起activated
deactivated
那么是在什么时候调用的呢?
src/core/instance/lifecycle.js
export function deactivateChildComponent (vm: Component, direct?: boolean) {
if (direct) {
vm._directInactive = true
if (isInInactiveTree(vm)) {
return
}
}
if (!vm._inactive) {
vm._inactive = true
for (let i = 0; i < vm.$children.length; i++) {
deactivateChildComponent(vm.$children[i])
}
callHook(vm, 'deactivated')
}
}
src/core/vdom/create-component.js
destroy (vnode: MountedComponentVNode) {
const { componentInstance } = vnode
if (!componentInstance._isDestroyed) {
if (!vnode.data.keepAlive) {
componentInstance.$destroy()
} else {
deactivateChildComponent(componentInstance, true /* direct */)
}
}
}
组件是vnode.data.keepAlive
的时候直接调用deactivateChildComponent
,发起deactivated
,不走$destroy
。
以上是VUE里面keep-alive中activated、deactivated两个点发生的生命周期位置,如果有误欢迎大家在评论里面指正。