# new vue 时发生了什么?
现在我们已经知道,vue本质上是一个构造函数。且在执行new vue(options)时,其内部执行了this._init(options)函数。那么这个函数中都做了哪些事情?
// core/instance/index.js
let uid = 0
Vue.prototype._init = function (options?: Object) {
// 当前vue实例
const vm: Component = this
// 维护uid,注意不是cid
vm._uid = uid++
// 做一个标示,以免被观察
vm._isVue = true
// 合并选项
if (options && options._isComponent) {
// 如果当前实例是内部组件
initInternalComponent(vm, options)
} else {
// 定义$options
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
// 这里为啥?
vm._renderProxy = vm
// 暴露自己
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
// 触发钩子: beforeCreate
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
// 触发钩子: created
callHook(vm, 'created')
// 如果传入了el,那么渲染
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# initLifecycle
初始化运行时所需要的基础内部变量
// core/instance/lifecycle.js
export function initLifecycle (vm: Component) {
const options = vm.$options
// 找到父亲元素,并且把子类(当前实例)push到父亲的children队列
let parent = options.parent
if (parent && !options.abstract) {
while (parent.$options.abstract && parent.$parent) {
parent = parent.$parent
}
parent.$children.push(vm)
}
// 父亲实例
vm.$parent = parent
// 根实例
vm.$root = parent ? parent.$root : vm
// children实例
vm.$children = []
// 定义refs
vm.$refs = {}
// 初始化内部变量
vm._watcher = null
vm._inactive = null
vm._directInactive = false
vm._isMounted = false
vm._isDestroyed = false
vm._isBeingDestroyed = false
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# initEvents
初始化和事件相关的内部变量
// core/instance/events.js
export function initEvents (vm: Component) {
// 初始化内部events相关变量
vm._events = Object.create(null)
vm._hasHookEvent = false
// init parent attached events
const listeners = vm.$options._parentListeners
if (listeners) {
updateComponentListeners(vm, listeners)
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# initRender
初始化和渲染相关的内部变量
// core/instance/render.js
export function initRender (vm: Component) {
// 虚拟dom,子树的跟节点
vm._vnode = null
// v-once 缓存的树
vm._staticTrees = null
const options = vm.$options
// 父节点的_vnode
const parentVnode = vm.$vnode = options._parentVnode
// 渲染上下文
const renderContext = parentVnode && parentVnode.context
// 当前实例的插槽节点
vm.$slots = resolveSlots(options._renderChildren, renderContext)
// 范围插槽
vm.$scopedSlots = emptyObject
/*
* 给当前实例绑定createElement方法
* createElement接受的变量,
* context: Component,上下文环境
* tag: any,
* data: any,
* children: any,
* normalizationType: any,归一化类型
* alwaysNormalize: boolean,简单或者正常渲染子节点
*/
// 内部版本由从模板编译的渲染函数使用
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
// 标准化公开版本,适用于用户自定义 render函数
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
// 父节点的data
const parentData = parentVnode && parentVnode.data
// 定义当前实例的$attrs,$listeners,数据来源于父节点对应的信息,浅监听
defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)
defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# initInjections
初始化依赖注入
// core/instance/inject.js
export function initInjections (vm: Component) {
const result = resolveInject(vm.$options.inject, vm)
if (result) {
toggleObserving(false)
Object.keys(result).forEach(key => {
defineReactive(vm, key, result[key])
})
toggleObserving(true)
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# initState
初始化组件状态,下一章节将详细讲这一部分
// core/instance/state.js
export function initState (vm: Component) {
// 当前实例的监听
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true /* asRootData */)
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# initProvide
初始化和inject相关的内部变量
// core/instance/inject.js
export function initProvide (vm: Component) {
const provide = vm.$options.provide
if (provide) {
vm._provided = typeof provide === 'function'
? provide.call(vm)
: provide
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 思维导图
← vue是什么(二)? 理解内部状态前的准备 →