@@ -3,7 +3,7 @@ title: vue源码解析
3
3
date : 2019-06-22 16:56:20
4
4
tags :
5
5
---
6
- ## 首先是入口文件: ` src/platforms/web/entry-runtime-with-compiler.js `
6
+ ## < span id = " entry " > 首先是入口文件: ` src/platforms/web/entry-runtime-with-compiler.js ` </ span >
7
7
8
8
做了哪些事情呢?
9
9
@@ -31,7 +31,7 @@ new Vue({
31
31
这里的` $mount ` 就是上面重写后的` Vue.prototype.$mount ` ,所以执行` $mount ` 时实际执行的是` mount.call(this, el, hydrating) ` ,也就是重写前的` Vue.prototype.$mount ` 。重写前的` Vue.prototype.$mount ` 来自` src/platforms/web/runtime/index.js ` 。我们去看一下这个文件里做了哪些事情。
32
32
33
33
34
- ## ` src/platforms/web/runtime/index.js `
34
+ ## < span id = " web-runtime-index " > ` src/platforms/web/runtime/index.js ` </ span >
35
35
做了哪些事情呢?
36
36
37
37
1 . 从` src/core/index ` 里导入` Vue `
@@ -70,3 +70,176 @@ new Vue({
70
70
可以看到这个文件里定义了我们执行的` $mount ` ,而返回的是` mountComponent(this, el, hydrating) ` ,这个` mountComponent ` 方法来自` src/core/instance/lifecycle ` 。
71
71
72
72
## ` src/core/instance/lifecycle `
73
+ ` mountComponent ` 函数做了哪些事情呢?
74
+
75
+ 1 . 设置` vm.$el ` : ` vm.$el = el `
76
+ 2 . 执行` beforeMount ` 钩子: ` callHook(vm, 'beforeMount') `
77
+ 3 . 实例化一个` watcher `
78
+ ``` javascript
79
+ new Watcher (vm, updateComponent, noop, {
80
+ before () {
81
+ if (vm ._isMounted && ! vm ._isDestroyed ) {
82
+ callHook (vm, ' beforeUpdate' )
83
+ }
84
+ }
85
+ }, true
86
+ ` ` `
87
+ 4. 执行` mounted` 钩子
88
+ ` ` ` javascript
89
+ if (vm .$vnode == null ) {
90
+ vm ._isMounted = true
91
+ callHook (vm, ' mounted' )
92
+ }
93
+ ` ` `
94
+ 5. 返回` return vm`
95
+
96
+ 可以看到这里就完成了整个组件的挂载,并且在这里调用了` new Watcher ` ,如果有更新,就执行` beforeUpdate` 钩子。
97
+
98
+ 这个` new Watcher ` 我们稍后再说。
99
+
100
+ 总结:上面这些是顺着` .$mount (' #app' )` 讲的,说明了执行` .$mount (' #app' )` 过程中做了什么事情。那么` new Vue ({// 这里是我们写的配置,对应的是this.$options})`这个实例化Vue的过程做了什么呢?请接着阅读下文
101
+
102
+
103
+ # Vue的实例化过程
104
+ 从[第一部分入口文件](#entry)和[第二部分](#web- runtime- index)分析可知,最终我们在` main.js` 里使用的` Vue` 来自` src/core/index.js` ,继续追踪` src/core/index.js` ,发现` Vue` 来自` src/core/instance/index.js` 。
105
+
106
+ ## ` src/core/instance/index.js`
107
+ 这个文件,定义了` Vue` 函数,然后下面执行的一系列函数,就是在Vue的原型上添加属性。
108
+
109
+ ` ` ` javascript
110
+ function Vue (options) {
111
+ if (process.env.NODE_ENV !== 'production' &&
112
+ !(this instanceof Vue)
113
+ ) {
114
+ warn('Vue is a constructor and should be called with the ` new ` keyword')
115
+ }
116
+ this._init(options)
117
+ }
118
+
119
+ initMixin(Vue)
120
+ stateMixin(Vue)
121
+ eventsMixin(Vue)
122
+ lifecycleMixin(Vue)
123
+ renderMixin(Vue)
124
+
125
+ export default Vue
126
+
127
+ ` ` `
128
+
129
+ 这一系列函数就是关键了。
130
+
131
+ ## ` initMixin`
132
+ 来自` src/core/instance/init.js` ,它在` Vue` 原型上设置了` _init` 方法(只是定义,没有执行),来看一下这个` _init` 方法:
133
+
134
+ 1. 设置` vm` 等于` this`
135
+ 2. 设置` vm.$options`
136
+ 3. 设置` vm._renderProxy`
137
+ 4. 设置` vm._self = vm`
138
+ 5. 初始化生命周期之类的:
139
+ ` ` ` javascript
140
+ initLifecycle(vm)
141
+ initEvents(vm)
142
+ initRender(vm)
143
+ callHook(vm, 'beforeCreate')
144
+ initInjections(vm) // resolve injections before data/props
145
+ initState(vm)
146
+ initProvide(vm) // resolve provide after data/props
147
+ callHook(vm, 'created')
148
+ ` ` `
149
+ 6. 如果有el,则执行$mount。
150
+
151
+ ### ` initLifecycle`
152
+ ` ` ` javascript
153
+ vm.$parent = parent
154
+ vm.$root = parent ? parent.$root : vm
155
+
156
+ vm.$children = []
157
+ vm.$refs = {}
158
+
159
+ vm._watcher = null
160
+ vm._inactive = null
161
+ vm._directInactive = false
162
+ vm._isMounted = false
163
+ vm._isDestroyed = false
164
+ vm._isBeingDestroyed = false
165
+ ` ` `
166
+
167
+ ### ` initEvents`
168
+ ` ` ` javascript
169
+ vm._events = Object.create(null)
170
+ vm._hasHookEvent = false
171
+ // init parent attached events
172
+ const listeners = vm.$options._parentListeners
173
+ if (listeners) {
174
+ updateComponentListeners(vm, listeners)
175
+ }
176
+ ` ` `
177
+
178
+ ### ` initRender`
179
+ ` ` ` javascript
180
+ vm._vnode = null // the root of the child tree
181
+ vm._staticTrees = null
182
+ vm.$slots
183
+ vm.$scopedSlots
184
+ vm._c
185
+ vm.$createElement
186
+ defineReactive(vm, '$attrs',...
187
+ defineReactive(vm, '$listeners',...
188
+ ` ` `
189
+
190
+ ### ` initInjections`
191
+ 解析inject,关闭响应式
192
+
193
+ ### ` initState`
194
+ 设置` vm._watchers = []`
195
+ 1. ` initProps`
196
+ 定义` vm._props`
197
+ 校验` props`
198
+ 关闭响应式,然后` defineReactive(props, key, value,...`
199
+ proxy (vm, ` _props` , key)
200
+ 2. ` initMethods` : ` vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)`
201
+ 3. ` initData`
202
+ 定义` vm._data`
203
+ ` proxy(vm, '_data', key)`
204
+ ` observe(data, true)`
205
+ 4. ` initComputed`
206
+ 定义` vm._computedWatchers`
207
+ 对每个key new 一个watcher
208
+ 5. ` initWatch`
209
+ ` createWatcher`
210
+
211
+ ### ` initProvide`
212
+ 设置` vm._provided` 为vm .$options .provide
213
+
214
+
215
+ ## ` stateMixin`
216
+ 来自` src/core/instance/state.js` :
217
+
218
+ 1. 定义` Vue.prototype.$data` ,其get方法是返回` this._data`
219
+ 2. 定义` Vue.prototype.$props` ,其get方法是返回` this._props`
220
+ 3. 定义` Vue.prototype.$set = set` , 这个` set` 来自` src/core/observer/index`
221
+ 4. 定义` Vue.prototype.$delete = del` , 这个` del` 来自` src/core/observer/index`
222
+ 5. 定义` Vue.prototype.$watch`
223
+
224
+ ## ` eventsMixin`
225
+ 来自` src/core/instance/event.js` :
226
+
227
+ 1. 定义` Vue.prototype.$on` 、` Vue.prototype.$once` 、` Vue.prototype.$off` 、` Vue.prototype.$emit`
228
+
229
+ ## ` lifecycleMixin`
230
+ 来自` src/core/instance/lifecycle.js` :
231
+
232
+ 1. 定义` Vue.prototype._update` 、` Vue.prototype.$forceUpdate` 、` Vue.prototype.$destroy`
233
+
234
+ ## ` renderMixin`
235
+ 来自` src/core/instance/render.js` :
236
+
237
+ 1. 执行` installRenderHelpers` ,略
238
+ 2. 定义` Vue.prototype.$nextTick`
239
+ 3. 定义` Vue.prototype._render`
240
+
241
+
242
+ # ` new Watcher`
243
+ 还记得我们上面分析` .$mount` 执行过程时,留着一个` new Watcher` 没说呢。` Watcher` 是在` src/core/observer/watcher.js` 里定义的。下面就开始分析:
244
+
245
+
0 commit comments