Skip to content

Commit 5abfc42

Browse files
author
YuChengKai
committed
finish vue lifecycle
1 parent 4e32bd0 commit 5abfc42

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

Framework/vue-zh.md

+126
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,129 @@ export function nextTick(cb?: Function, ctx?: Object) {
6969

7070
# 生命周期分析
7171

72+
生命周期函数就是组件在初始化或者数据更新时会触发的钩子函数。
73+
74+
![](https://user-gold-cdn.xitu.io/2018/7/12/1648d9df78201f07?w=1200&h=3039&f=png&s=50021)
75+
76+
在初始化时,会调用以下代码,生命周期就是通过 `callHook` 调用的
77+
78+
```js
79+
Vue.prototype._init = function(options) {
80+
initLifecycle(vm)
81+
initEvents(vm)
82+
initRender(vm)
83+
callHook(vm, 'beforeCreate') // 拿不到 props data
84+
initInjections(vm)
85+
initState(vm)
86+
initProvide(vm)
87+
callHook(vm, 'created')
88+
}
89+
```
90+
91+
可以发现在以上代码中,`beforeCreate` 调用的时候,是获取不到 props 或者 data 中的数据的,因为这些数据的初始化都在 `initState` 中。
92+
93+
接下来会执行挂载函数
94+
95+
```js
96+
export function mountComponent {
97+
callHook(vm, 'beforeMount')
98+
// ...
99+
if (vm.$vnode == null) {
100+
vm._isMounted = true
101+
callHook(vm, 'mounted')
102+
}
103+
}
104+
```
105+
106+
`beforeMount` 就是在挂载前执行的,然后开始创建 VDOM 并替换成真实 DOM,最后执行 `mounted` 钩子。这里会有个判断逻辑,如果是外部 `new Vue({}) ` 的话,不会存在 `$vnode` ,所以直接执行 ``mounted`` 钩子了。如果有子组件的话,会递归挂载子组件,只有当所有子组件全部挂载完毕,才会执行根组件的挂载钩子。
107+
108+
接下来是数据更新时会调用的钩子函数
109+
110+
```js
111+
function flushSchedulerQueue() {
112+
// ...
113+
for (index = 0; index < queue.length; index++) {
114+
watcher = queue[index]
115+
if (watcher.before) {
116+
watcher.before() // 调用 beforeUpdate
117+
}
118+
id = watcher.id
119+
has[id] = null
120+
watcher.run()
121+
// in dev build, check and stop circular updates.
122+
if (process.env.NODE_ENV !== 'production' && has[id] != null) {
123+
circular[id] = (circular[id] || 0) + 1
124+
if (circular[id] > MAX_UPDATE_COUNT) {
125+
warn(
126+
'You may have an infinite update loop ' +
127+
(watcher.user
128+
? `in watcher with expression "${watcher.expression}"`
129+
: `in a component render function.`),
130+
watcher.vm
131+
)
132+
break
133+
}
134+
}
135+
}
136+
callUpdatedHooks(updatedQueue)
137+
}
138+
139+
function callUpdatedHooks(queue) {
140+
let i = queue.length
141+
while (i--) {
142+
const watcher = queue[i]
143+
const vm = watcher.vm
144+
if (vm._watcher === watcher && vm._isMounted) {
145+
callHook(vm, 'updated')
146+
}
147+
}
148+
}
149+
```
150+
151+
上图还有两个生命周期没有说,分别为 `activated``deactivated` ,这两个钩子函数是 `keep-alive` 组件独有的。用 `keep-alive` 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 `deactivated` 钩子函数,命中缓存渲染后会执行 `actived` 钩子函数。
152+
153+
最后就是销毁组件的钩子函数了
154+
155+
```js
156+
Vue.prototype.$destroy = function() {
157+
// ...
158+
callHook(vm, 'beforeDestroy')
159+
vm._isBeingDestroyed = true
160+
// remove self from parent
161+
const parent = vm.$parent
162+
if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
163+
remove(parent.$children, vm)
164+
}
165+
// teardown watchers
166+
if (vm._watcher) {
167+
vm._watcher.teardown()
168+
}
169+
let i = vm._watchers.length
170+
while (i--) {
171+
vm._watchers[i].teardown()
172+
}
173+
// remove reference from data ob
174+
// frozen object may not have observer.
175+
if (vm._data.__ob__) {
176+
vm._data.__ob__.vmCount--
177+
}
178+
// call the last hook...
179+
vm._isDestroyed = true
180+
// invoke destroy hooks on current rendered tree
181+
vm.__patch__(vm._vnode, null)
182+
// fire destroyed hook
183+
callHook(vm, 'destroyed')
184+
// turn off all instance listeners.
185+
vm.$off()
186+
// remove __vue__ reference
187+
if (vm.$el) {
188+
vm.$el.__vue__ = null
189+
}
190+
// release circular reference (#6759)
191+
if (vm.$vnode) {
192+
vm.$vnode.parent = null
193+
}
194+
}
195+
```
196+
197+
在执行销毁操作前会调用 `beforeDestroy` 钩子函数,然后进行一系列的销毁操作,如果有子组件的话,也会递归销毁子组件,所有子组件都销毁完毕后才会执行根组件的 `destroyed` 钩子函数。

0 commit comments

Comments
 (0)