Skip to content

Commit

Permalink
finish vue lifecycle
Browse files Browse the repository at this point in the history
  • Loading branch information
YuChengKai committed Jul 13, 2018
1 parent 4e32bd0 commit 5abfc42
Showing 1 changed file with 126 additions and 0 deletions.
126 changes: 126 additions & 0 deletions Framework/vue-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,129 @@ export function nextTick(cb?: Function, ctx?: Object) {

# 生命周期分析

生命周期函数就是组件在初始化或者数据更新时会触发的钩子函数。

![](https://user-gold-cdn.xitu.io/2018/7/12/1648d9df78201f07?w=1200&h=3039&f=png&s=50021)

在初始化时,会调用以下代码,生命周期就是通过 `callHook` 调用的

```js
Vue.prototype._init = function(options) {
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate') // 拿不到 props data
initInjections(vm)
initState(vm)
initProvide(vm)
callHook(vm, 'created')
}
```

可以发现在以上代码中,`beforeCreate` 调用的时候,是获取不到 props 或者 data 中的数据的,因为这些数据的初始化都在 `initState` 中。

接下来会执行挂载函数

```js
export function mountComponent {
callHook(vm, 'beforeMount')
// ...
if (vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')
}
}
```

`beforeMount` 就是在挂载前执行的,然后开始创建 VDOM 并替换成真实 DOM,最后执行 `mounted` 钩子。这里会有个判断逻辑,如果是外部 `new Vue({}) ` 的话,不会存在 `$vnode` ,所以直接执行 ``mounted`` 钩子了。如果有子组件的话,会递归挂载子组件,只有当所有子组件全部挂载完毕,才会执行根组件的挂载钩子。

接下来是数据更新时会调用的钩子函数

```js
function flushSchedulerQueue() {
// ...
for (index = 0; index < queue.length; index++) {
watcher = queue[index]
if (watcher.before) {
watcher.before() // 调用 beforeUpdate
}
id = watcher.id
has[id] = null
watcher.run()
// in dev build, check and stop circular updates.
if (process.env.NODE_ENV !== 'production' && has[id] != null) {
circular[id] = (circular[id] || 0) + 1
if (circular[id] > MAX_UPDATE_COUNT) {
warn(
'You may have an infinite update loop ' +
(watcher.user
? `in watcher with expression "${watcher.expression}"`
: `in a component render function.`),
watcher.vm
)
break
}
}
}
callUpdatedHooks(updatedQueue)
}

function callUpdatedHooks(queue) {
let i = queue.length
while (i--) {
const watcher = queue[i]
const vm = watcher.vm
if (vm._watcher === watcher && vm._isMounted) {
callHook(vm, 'updated')
}
}
}
```

上图还有两个生命周期没有说,分别为 `activated``deactivated` ,这两个钩子函数是 `keep-alive` 组件独有的。用 `keep-alive` 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 `deactivated` 钩子函数,命中缓存渲染后会执行 `actived` 钩子函数。

最后就是销毁组件的钩子函数了

```js
Vue.prototype.$destroy = function() {
// ...
callHook(vm, 'beforeDestroy')
vm._isBeingDestroyed = true
// remove self from parent
const parent = vm.$parent
if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
remove(parent.$children, vm)
}
// teardown watchers
if (vm._watcher) {
vm._watcher.teardown()
}
let i = vm._watchers.length
while (i--) {
vm._watchers[i].teardown()
}
// remove reference from data ob
// frozen object may not have observer.
if (vm._data.__ob__) {
vm._data.__ob__.vmCount--
}
// call the last hook...
vm._isDestroyed = true
// invoke destroy hooks on current rendered tree
vm.__patch__(vm._vnode, null)
// fire destroyed hook
callHook(vm, 'destroyed')
// turn off all instance listeners.
vm.$off()
// remove __vue__ reference
if (vm.$el) {
vm.$el.__vue__ = null
}
// release circular reference (#6759)
if (vm.$vnode) {
vm.$vnode.parent = null
}
}
```

在执行销毁操作前会调用 `beforeDestroy` 钩子函数,然后进行一系列的销毁操作,如果有子组件的话,也会递归销毁子组件,所有子组件都销毁完毕后才会执行根组件的 `destroyed` 钩子函数。

0 comments on commit 5abfc42

Please sign in to comment.