vue2.x源码剖析连串二: Vue组件开始化进度大约

2018/08/02 · JavaScript
· Vue

原版的书文出处:
lihongxun945   

此地深入分析的是时下(2018/07/25)最新版 V2.5.16
的源码,如若您想三次看叁遍参阅源码,请必需记得切换成此版本,不然可能存在微小的距离。

澳门凯旋门注册网址 1

世家都精晓,我们的应用是三个由Vue组件构成的一棵树,在那之中每二个节点都以多个Vue
组件。大家的每五个Vue组件是哪些被成立出来的,创立的历程经历了什么样步骤呢?把那么些都搞明白,那么大家对Vue的满贯原理将会有很深刻的接头。

从入口函数开首,有比较复杂的援引关系,为了方便大家知晓,作者画了一张图能够直观地看出她们之间的涉嫌:

澳门凯旋门注册网址 2

创设Vue实例的两步

大家成立一个Vue实例,只要求两行代码:

JavaScript

import Vue from ‘vue’ new Vue(options)

1
2
import Vue from ‘vue’
new Vue(options)

而这两步分别经历了二个比较复杂的塑造进程:

  1. 制造类:创建贰个 Vue 构造函数,以及她的一多级原型方法和类格局
  2. 澳门凯旋门游戏网址,创设实例:创设三个 Vue 实例,伊始化他的数据,事件,模板等

上边大家分别深入分析这多少个等第,在那之中种种阶段 又分为好三个 步骤

首先阶段:创设Vue类

首先阶段是要创建二个Vue类,因为大家那边用的是原型并非ES6中的class注明,所以拆成了三步来促成:

  1. 创制三个构造函数 Vue
  2. Vue.prototype 上创制一多元实例属性方法,举例 this.$data
  3. Vue 上创建一些大局方法,比方 Vue.use 能够挂号插件

小编们导入 Vue 构造函数 import Vue from ‘vue’ 的时候(new Vue(options)
在此之前),会转移一个Vue的构造函数,那些构造函数本身非常的粗略,但是他方面会增添一文山会海的实例方法和一些大局方法,让大家跟着代码来所有人家看看如何一步步构造多个Vue
类的,大家要清楚每一步大致是做什么的,可是此地先不追究,因为大家会在接下去几章具体讲授每一步都做了什么,这里大家先有多个大致的概念就可以。

大家看代码先从进口起初,那是我们在浏览器情况最常用的贰个进口,也正是大家
import Vue 的时候一向导入的,它很简短,直接回到了 从
platforms/web/runtime/index/js 中得到的 Vue 构造函数,具体代码如下:

platforms/web/entry-runtime.js

JavaScript

import Vue from ‘./runtime/index’ export default Vue

1
2
import Vue from ‘./runtime/index’
export default Vue

能够看出,这里不是 Vue
构造函数的概念地点,而是回到了从上边一步获得的Vue构造函数,可是做了一部分平台相关的操作,比如内置
directives
注册等。这里就能够有人问了,为啥不直接定义一个构造函数,而是那样不停的传递呢?因为
vue 有例外的运作境况,而每二个条件又有带不带 compiler
等分歧版本,所以情况的不及以及版本的不如都会导致 Vue
类会有局部异样,那么这里会经过差异的步调来拍卖那些差别,而具有的情状版本都要用到的基本代码是同样的,由此这个一样的代码就集结到
core/中了。

总体代码和笔者加的笺注如下:

platforms/web/runtime/index.js

import Vue from ‘core/index’ import config from ‘core/config’ // 省略
import platformDirectives from ‘./directives/index’ import
platformComponents from ‘./components/index’
//这里都是web平台相关的某些布局 // install platform specific utils
Vue.config.mustUseProp = mustUseProp // 省略 // 注册指令和组件,这里的
directives 和 components 也是web平台上的,是停放的吩咐和零部件,其实少之甚少// install platform runtime directives & components
extend(Vue.options.directives, platformDirectives) //
内置的directives唯有七个,`v-show` 和 `v-model`
extend(Vue.options.components, platformComponents) //
内置的零件也相当少,独有`keepAlive`, `transition`和
`澳门凯旋门注册网址,transitionGroup` // 假如不是浏览器,就不进行 `patch` 操作了 //
install platform patch function Vue.prototype.__patch__ = inBrowser
? patch : noop // 如果有 `el` 且在浏览器中,则实行 `mount` 操作 //
public mount method Vue.prototype.$mount = function ( el?: string |
Element, hydrating?: boolean ): Component { el = el && inBrowser ?
query(el) : undefined return mountComponent(this, el, hydrating) } //
省略devtool相关代码 export default Vue

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
import Vue from ‘core/index’
import config from ‘core/config’
// 省略
 
import platformDirectives from ‘./directives/index’
import platformComponents from ‘./components/index’
 
//这里都是web平台相关的一些配置
// install platform specific utils
Vue.config.mustUseProp = mustUseProp
// 省略
 
// 注册指令和组件,这里的 directives 和 components 也是web平台上的,是内置的指令和组件,其实很少
// install platform runtime directives & components
extend(Vue.options.directives, platformDirectives) // 内置的directives只有两个,`v-show` 和 `v-model`
extend(Vue.options.components, platformComponents) // 内置的组件也很少,只有`keepAlive`, `transition`和 `transitionGroup`
 
// 如果不是浏览器,就不进行 `patch` 操作了
// install platform patch function
Vue.prototype.__patch__ = inBrowser ? patch : noop
 
// 如果有 `el` 且在浏览器中,则进行 `mount` 操作
// public mount method
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
  el = el && inBrowser ? query(el) : undefined
  return mountComponent(this, el, hydrating)
}
 
// 省略devtool相关代码
 
export default Vue

下边包车型地铁代码终于把阳台和陈设相关的逻辑都处理完了,大家能够进去到了 core
目录,这里是Vue组件的为主代码,大家率先步向 core/index文件,发现
Vue
构造函数亦不是在这里定义的。不过这里有点值得注意的就是,这里调用了三个
initGlobalAPI 函数,那几个函数是增进一些大局属性方法到 Vue
上,也等于类措施,并非实例方法。具体他是做什么的我们后边再讲

core/index.js

import Vue from ‘./instance/index’ import { initGlobalAPI } from
‘./global-api/index’ initGlobalAPI(Vue) // 这么些函数增添了一些类措施属性
// 省略有个别ssr相关的原委 // 省略 Vue.version = ‘__VERSION__’ export
default Vue

1
2
3
4
5
6
7
8
9
10
11
import Vue from ‘./instance/index’
import { initGlobalAPI } from ‘./global-api/index’
 
initGlobalAPI(Vue) // 这个函数添加了一些类方法属性
 
// 省略一些ssr相关的内容
// 省略
 
Vue.version = ‘__VERSION__’
 
export default Vue

core/instance/index.js 这里才是的确的创始了 Vue
构造函数的地点,即使代码也很简单,正是创制了二个构造函数,然后经过mixin把一批实例方法增多上去。

core/instance/index.js 完整代码如下:

// 省略import语句 function Vue (options) { if (process.env.NODE_凯旋门074网址,ENV !==
‘production’ && !(this instanceof Vue) ) { warn(‘Vue is a constructor
and should be called with the `new` keyword’) } this._init(options) }
initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue)
renderMixin(Vue) export default Vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//  省略import语句
function Vue (options) {
  if (process.env.NODE_ENV !== ‘production’ &&
    !(this instanceof Vue)
  ) {
    warn(‘Vue is a constructor and should be called with the `new` keyword’)
  }
  this._init(options)
}
 
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
 
export default Vue

上边大家分成两段来教学这个代码分别干了怎么样。

function Vue (options) { if (process.env.NODE_ENV !== ‘production’ &&
!(this instanceof Vue) ) { warn(‘Vue is a constructor and should be
called with the `new` keyword’) } this._init(options) //
构造函数有用的唯有这一行代码,是或不是很简单,至于这一行代码具体做了什么样,在其次品级大家详细解说。
}

1
2
3
4
5
6
7
8
function Vue (options) {
  if (process.env.NODE_ENV !== ‘production’ &&
    !(this instanceof Vue)
  ) {
    warn(‘Vue is a constructor and should be called with the `new` keyword’)
  }
  this._init(options) // 构造函数有用的只有这一行代码,是不是很简单,至于这一行代码具体做了什么,在第二阶段我们详细讲解。
}

此处才是真的的Vue构造函数,注意其实很轻便,忽略在付出形式下的警戒外,只举行了一行代码
this._init(options)。总之,Vue初叶化必定有众多做事要做,例如数据的响应用化学、事件的绑定等,在其次等级大家会详细解说这些函数到底做了哪些。这里我们一时半刻跳过它。

initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue)
renderMixin(Vue)

1
2
3
4
5
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

地点那五个函数其实都以在Vue.prototype上增多了部分品质方法,让我们先找一个走访现实的代码,比方initMixin
正是增添 _init 函数,没有错就是大家构造函数中调用的不行
this._init(options)
哦,它在那之中首若是调用其余的多少个早先化方法,因为相比简单,我们一直看代码:

一经你想二遍看一次参阅源码。core/instance/init.js

export function initMixin (Vue: Class<Component>) { //
就是此处,增添了叁个方法 Vue.prototype._init = function (options?:
Object) { // 省略,那有些我们会在第二品级讲明 } }

1
2
3
4
5
6
export function initMixin (Vue: Class<Component>) {
  // 就是这里,添加了一个方法
  Vue.prototype._init = function (options?: Object) {
    // 省略,这部分我们会在第二阶段讲解
  }
}

别的的多少个一样都以在 Vue.prototype
上增加了一些措施,这里一时先不一个个贴代码,总括一下之类:

  1. core/instance/state.js,主即使增添了
    $data,$props,$watch,$set,$delete 多少个属性和措施
  2. core/instance/events.js,主就算增添了
    $on,$off,$once,$emit 八个法子
  3. core/instance/lifecycle.js,首要增添了 _update,
    $forceUpdate, $destroy 多个主意
  4. core/instance/renderMixin.js,首要增多了 $nextTick
    _render 八个艺术以及一大堆renderHelpers

还记得我们跳过的在core/index.js中 添加
globalAPI的代码吗,后面的代码都是在 Vue.prototype
上加多实例属性,让大家回到 core/index 文件,这一步供给在 Vue一经你想二遍看一次参阅源码。
上增多一些大局属性方法。前面讲到过,是透过 initGlobalAPI
来增添的,那么大家一贯看看那个函数的标准:

export function initGlobalAPI (Vue: GlobalAPI) { // config const
configDef = {} configDef.get = () => config // 省略 //
这里增添了贰个`Vue.config` 对象,至于在何地会用到,前边会讲
Object.defineProperty(Vue, ‘config’, configDef) // exposed util methods.
// NOTE: these are not considered part of the public API – avoid relying
on // them unless you are aware of the risk. Vue.util = { warn, extend,
mergeOptions, defineReactive } //平时大家用实例方法并非那七个类措施
Vue.set = set Vue.delete = del Vue.nextTick = nextTick //
注意这里,循环出来的结果其实是四个 `components`,`directives`,
`filters`,这里先创立了空对象作为容器,前边假若有相应的插件就能够放进来。
Vue.options = Object.create(null) ASSET_TYPES.forEach(type => {
Vue.options[一经你想二遍看一次参阅源码。type + ‘s’] = Object.create(null) }) // this is used to
identify the “base” constructor to extend all plain-object // components
with in Weex’s multi-instance scenarios. Vue.options._base = Vue //
内置组件独有三个,正是 `keepAlive` extend(Vue.options.components,
builtInComponents) initUse(Vue) // 增添了 Vue.use 方法,可以挂号插件
initMixin(Vue) //加多了Vue.mixin 方法 initExtend(Vue) // 增加了
Vue.extend 方法 // 这一步是登记了 `Vue.component` ,`Vue.directive`
和 `Vue.filter` 多少个点子,上边不是有 `Vue.options.components`
等空对象啊,那多个艺术的效用正是把注册的组件放入对应的器皿中。
initAssetRegisters(Vue) }

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
export function initGlobalAPI (Vue: GlobalAPI) {
  // config
  const configDef = {}
  configDef.get = () => config
  // 省略
 
  // 这里添加了一个`Vue.config` 对象,至于在哪里会用到,后面会讲
  Object.defineProperty(Vue, ‘config’, configDef)
 
  // exposed util methods.
  // NOTE: these are not considered part of the public API – avoid relying on
  // them unless you are aware of the risk.
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }
  
  //一般我们用实例方法而不是这三个类方法
  Vue.set = set
  Vue.delete = del
  Vue.nextTick = nextTick
  
  // 注意这里,循环出来的结果其实是三个 `components`,`directives`, `filters`,这里先创建了空对象作为容器,后面如果有对应的插件就会放进来。
  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + ‘s’] = Object.create(null)
  })
 
  // this is used to identify the "base" constructor to extend all plain-object
  // components with in Weex’s multi-instance scenarios.
  Vue.options._base = Vue
 
  // 内置组件只有一个,就是 `keepAlive`
  extend(Vue.options.components, builtInComponents)
 
  initUse(Vue) // 添加了 Vue.use 方法,可以注册插件
  initMixin(Vue) //添加了Vue.mixin 方法
  initExtend(Vue) // 添加了 Vue.extend 方法
 
  // 这一步是注册了 `Vue.component` ,`Vue.directive` 和 `Vue.filter` 三个方法,上面不是有 `Vue.options.components` 等空对象吗,这三个方法的作用就是把注册的组件放入对应的容器中。
  initAssetRegisters(Vue)
}

迄今截至,我们就营造出了贰个 Vue
类,这一个类上的方式都已增添落成。这里再度强调一次,这么些品级只是拉长办法并非举办他们,具体施行他们是要到第二等第的。计算一下,大家创设的Vue类都蕴含了什么内容:

//构造函数 function Vue () { this._init() }
//全局config对象,大家大约不会用到 Vue.config = { keyCodes,
_lifecycleHooks: [‘beforeCreate’, ‘created’, …] } //
暗中认可的options配置,大家各种组件都会继续这一个布局。 Vue.options = {
beforeCreate, // 比如 vue-router 就能登记这么些回调,因而会每一个零件承接components, // 前边提到了,私下认可组件有多个 `KeepAlive`,`transition`,
`transitionGroup`,这里登记的零部件正是全局组件,因为别的四个零件中不要申明就能够用了。所以全局组件的准绳正是如此轻松directives, // 暗许独有 `v-show` 和 `v-model` filters //
不引入应用了 } //一些大局方法 Vue.use // 注册插件 Vue.component //
注册组件 Vue.directive // 注册指令 Vue.nextTick //下一个tick施行函数
Vue.set/delete // 数据的改换操作 Vue.mixin // 混入mixin用的
//Vue.prototype 上有两种差别作用的主意 //由initMixin 增加的 `_init`
方法,是Vue实例早先化的入口方法,会调用别的的功力初阶话函数
Vue.prototype._一经你想二遍看一次参阅源码。init // 由 initState 增加的八个用来打开多少操作的办法
Vue.prototype.$data Vue.prototype.$props Vue.prototype.$watch //
由init伊夫nts增多的平地风波措施 Vue.prototype.$on Vue.prototype.$off
Vue.prototype.$one Vue.prototype.$emit // 由
lifecycle加多的生命周期相关的主意 Vue.prototype._update
Vue.prototype.$forceUpdate Vue.prototype.$destroy //在 platform
中增进的生命周期方法 Vue.prototype.$mount //
由renderMixin增添的`$nextTick` 和 `_render` 以及一批renderHelper
Vue.prototype.$nextTick Vue.prototype._render Vue.prototype._b
Vue.prototype._e //…

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
46
47
48
49
50
51
52
53
54
55
56
57
//构造函数
function Vue () {
  this._init()
}
 
//全局config对象,我们几乎不会用到
Vue.config = {
  keyCodes,
  _lifecycleHooks: [‘beforeCreate’, ‘created’, …]
}
 
// 默认的options配置,我们每个组件都会继承这个配置。
Vue.options = {
  beforeCreate, // 比如 vue-router 就会注册这个回调,因此会每一个组件继承
  components, // 前面提到了,默认组件有三个 `KeepAlive`,`transition`, `transitionGroup`,这里注册的组件就是全局组件,因为任何一个组件中不用声明就能用了。所以全局组件的原理就是这么简单
  directives, // 默认只有 `v-show` 和 `v-model`
  filters // 不推荐使用了
}
 
//一些全局方法
Vue.use // 注册插件
Vue.component // 注册组件
Vue.directive // 注册指令
Vue.nextTick //下一个tick执行函数
Vue.set/delete // 数据的修改操作
Vue.mixin // 混入mixin用的
 
//Vue.prototype 上有几种不同作用的方法
 
//由initMixin 添加的 `_init` 方法,是Vue实例初始化的入口方法,会调用其他的功能初始话函数
Vue.prototype._init
 
// 由 initState 添加的三个用来进行数据操作的方法
Vue.prototype.$data
Vue.prototype.$props
Vue.prototype.$watch
 
// 由initEvents添加的事件方法
Vue.prototype.$on
Vue.prototype.$off
Vue.prototype.$one
Vue.prototype.$emit
 
// 由 lifecycle添加的生命周期相关的方法
Vue.prototype._update
Vue.prototype.$forceUpdate
Vue.prototype.$destroy
 
//在 platform 中添加的生命周期方法
Vue.prototype.$mount
 
// 由renderMixin添加的`$nextTick` 和 `_render` 以及一堆renderHelper
Vue.prototype.$nextTick
Vue.prototype._render
Vue.prototype._b
Vue.prototype._e
//…

上述正是大家的 Vue
类的全方位了,有一部分特意细小的点一时髦未列出来,若是您在末端看代码的时候,开掘有哪些函数不知底在哪定义的,能够参见这里。那么让大家进来第叁个级次:创立实例阶段

第二品级:创造 Vue 实例

作者们透过 new Vue(options)
来创造三个实例,实例的始建,料定是从构造函数开端的,然后博览会开一俯拾皆已的先导化操作,大家逐条看一下创办进度都进展了如何手化操作:

core/instance/index.js, 构造函数自个儿只进行了一个操作,正是调用
this._init(options) 进行初步化,这些在前面也涉及过,这里就不贴代码了。

core/instance/init.js
中会实行真正的初阶化操作,让我们详细看一下以此函数具体都做了些什么。

先看看它的完好代码:

Vue.prototype._init = function (options?: Object) { const vm: Component
= this // a uid vm._uid = uid++ let startTag, endTag /* istanbul
ignore if */ if (process.env.NODE_ENV !== ‘production’ &&
config.performance && mark) { startTag = `vue-perf-start:${vm._uid}`
endTag = `vue-perf-end:${vm._uid}` mark(startTag) } // a flag to
avoid this being observed vm._isVue = true // merge options if (options
&& options._isComponent) { // optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the //
internal component options needs special treatment.
initInternalComponent(vm, options) } else { vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor), options || {}, vm ) } /*
istanbul ignore else */ if (process.env.NODE_ENV !== ‘production’) {
initProxy(vm) } else { vm._renderProxy = vm } // expose real self
vm._self = vm initLifecycle(vm) initEvents(vm) initRender(vm)
callHook(vm, ‘beforeCreate’) initInjections(vm) // resolve injections
before data/props initState(vm) initProvide(vm) // resolve provide after
data/props callHook(vm, ‘created’) /* istanbul ignore if */ if
(process.env.NODE_ENV !== ‘production’ && config.performance && mark) {
vm._name = formatComponentName(vm, false) mark(endTag) measure(`vue
${vm._name} init`, startTag, endTag) } 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
46
47
48
49
50
51
52
53
54
55
56
Vue.prototype._init = function (options?: Object) {
  const vm: Component = this
  // a uid
  vm._uid = uid++
 
  let startTag, endTag
  /* istanbul ignore if */
  if (process.env.NODE_ENV !== ‘production’ && config.performance && mark) {
    startTag = `vue-perf-start:${vm._uid}`
    endTag = `vue-perf-end:${vm._uid}`
    mark(startTag)
  }
 
  // a flag to avoid this being observed
  vm._isVue = true
  // merge options
  if (options && options._isComponent) {
    // optimize internal component instantiation
    // since dynamic options merging is pretty slow, and none of the
    // internal component options needs special treatment.
    initInternalComponent(vm, options)
  } else {
    vm.$options = mergeOptions(
      resolveConstructorOptions(vm.constructor),
      options || {},
      vm
    )
  }
  /* istanbul ignore else */
  if (process.env.NODE_ENV !== ‘production’) {
    initProxy(vm)
  } else {
    vm._renderProxy = vm
  }
  // expose real self
  vm._self = vm
  initLifecycle(vm)
  initEvents(vm)
  initRender(vm)
  callHook(vm, ‘beforeCreate’)
  initInjections(vm) // resolve injections before data/props
  initState(vm)
  initProvide(vm) // resolve provide after data/props
  callHook(vm, ‘created’)
 
  /* istanbul ignore if */
  if (process.env.NODE_ENV !== ‘production’ && config.performance && mark) {
    vm._name = formatComponentName(vm, false)
    mark(endTag)
    measure(`vue ${vm._name} init`, startTag, endTag)
  }
 
  if (vm.$options.el) {
    vm.$mount(vm.$options.el)
  }
}

笔者们来一段一段看看下面的代码分别作了哪些。

const vm: Component = this // vm 便是this的一个别称而已 // a uid
vm._uid = uid++ // 唯一自增ID let startTag, endTag /* istanbul ignore
if */ if (process.env.NODE_ENV !== ‘production’ && config.performance
&& mark) { startTag = `vue-perf-start:${vm._uid}` endTag =
`vue-perf-end:${vm._uid}` mark(startTag) }

1
2
3
4
5
6
7
8
9
10
11
    const vm: Component = this // vm 就是this的一个别名而已
    // a uid
    vm._uid = uid++ // 唯一自增ID
 
    let startTag, endTag
    /* istanbul ignore if */
    if (process.env.NODE_ENV !== ‘production’ && config.performance && mark) {
      startTag = `vue-perf-start:${vm._uid}`
      endTag = `vue-perf-end:${vm._uid}`
      mark(startTag)
    }

这段代码首先生成了贰个大局独一的id。然后一旦是非生产条件况兼张开了
performance,那么会调用 mark
进行performance标识,这段代码就是开辟方式下搜罗品质数据的,因为和Vue本人的运维原理无关,我们先跳过。

// a flag to avoid this being observed vm._isVue = true // merge
options // // TODO if (options && options._isComponent) { // optimize
internal component instantiation // since dynamic options merging is
pretty slow, and none of the // internal component options needs special
treatment. initInternalComponent(vm, options) } else { // mergeOptions
本人比较轻巧,正是做了七个合併操作 vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor), options || {}, vm ) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    // a flag to avoid this being observed
    vm._isVue = true
    // merge options
    //
    // TODO
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options)
    } else {
      // mergeOptions 本身比较简单,就是做了一个合并操作
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }

地点这段代码,临时先不用管_isComponent,权且只需求知道我们和好成本的时候利用的机件,都不是
_isComponent,所以大家会进去到 else语句中。这里主假若扩充了
options的联结,最后生成了贰个 $options 属性。下一章大家会详细疏解
options
合併的时候都做了何等,这里大家只要求权且知道,他是把构造函数上的options和大家创制组件时传出的布局
options 进行了叁个会集就足以了。即是出于联合了那个全局的 options
所以大家在能够直接在组件中接纳全局的 directives

/* istanbul ignore else */ if (process.env.NODE_ENV !== ‘production’)
{ initProxy(vm) } else { vm._renderProxy = vm }

1
2
3
4
5
6
  /* istanbul ignore else */
    if (process.env.NODE_ENV !== ‘production’) {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }

这段代码或者看起来相比奇异,那一个 renderProxy
是干嘛的吗,其实正是概念了在 render
函数渲染模板的时候,访谈属性的时候的三个代理,能够见到生产条件下就是温馨。

支付遇到下作了二个哪些操作呢?权且不要关注,反正知道渲染模板的时候上下文正是
vm 也就是 this
就行了。假若有意思味能够看看非生产情状,作了某些和谐的报错提示等。

此处只要求记住,在生养遇到下,模板渲染的上下文正是 vm就行了。

// expose real self vm._self = vm initLifecycle(vm) //
做了部分生命周期的初阶化专业,初始化了不知凡几变量,最重假使安装了老爹和儿子组件的引用关系,也正是设置了
`$parent` 和 `$children`的值 init伊芙nts(vm) //
注册事件,注意这里登记的不是投机的,而是父组件的。因为很显然父组件的监听器才会登记到儿女身上。
initRender(vm) // 做一些 render
的策动职业,比方拍卖父亲和儿子承继关系等,并不曾真的初始 render callHook(vm,
‘beforeCreate’) // 策画干活到位,接下去走入 `create` 阶段
initInjections(vm) // resolve injections before data/props initState(vm)
// `data`, `props`, `computed`
等都以在此间伊始化的,常见的面试考试的地方举个例子`Vue是哪些兑现多少响应用化学的`
答案就在那个函数中检索 initProvide(vm) // resolve provide after
data/props callHook(vm, ‘created’) // 至此 `create` 阶段完毕

1
2
3
4
5
6
7
8
9
10
11
  // expose real self
    vm._self = vm
 
    initLifecycle(vm) // 做了一些生命周期的初始化工作,初始化了很多变量,最主要是设置了父子组件的引用关系,也就是设置了 `$parent` 和 `$children`的值
    initEvents(vm) // 注册事件,注意这里注册的不是自己的,而是父组件的。因为很明显父组件的监听器才会注册到孩子身上。
    initRender(vm) // 做一些 render 的准备工作,比如处理父子继承关系等,并没有真的开始 render
    callHook(vm, ‘beforeCreate’) // 准备工作完成,接下来进入 `create` 阶段
    initInjections(vm) // resolve injections before data/props
    initState(vm) // `data`, `props`, `computed` 等都是在这里初始化的,常见的面试考点比如`Vue是如何实现数据响应化的` 答案就在这个函数中寻找
    initProvide(vm) // resolve provide after data/props
    callHook(vm, ‘created’) // 至此 `create` 阶段完成

这一段代码承担了组件开头化的大许多办事。小编间接把每一步的功效写在讲解里面了。
把那多少个函数都弄懂,那么大家也就多数弄懂了Vue的总体办事原理,而我辈接下去的几篇小说,其实都以从那多少个函数中的某二个从头的。

if (vm.$options.el) { vm.$mount(vm.$options.el) } } }

1
2
3
4
5
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
}

开首mount,注意这里假使是我们的options中内定了 el 才会在那边展开
$mount,而貌似意况下,大家是不安装 el 而是通过一向调用
$mount("#app") 来触发的。比方平常大家都是那样的:

new Vue({ router, store, i18n, render: h => h(App) }).$mount(‘#app’)

1
2
3
4
5
6
new Vue({
  router,
  store,
  i18n,
  render: h => h(App)
}).$mount(‘#app’)

以上正是Vue实例的开头化进度。因为在 create 阶段和 $mount
阶段都很复杂,所现在边会分多少个章节来分别详细批注。下一篇,让大家从最神秘的多少响应化谈到。

1 赞 收藏
评论

澳门凯旋门注册网址 3

相关文章