持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
在本篇文章中,作者会简单的介绍下new Vue()的流程,来帮助读者更好的理解vue背后的执行原理。
第一步
在vue的构造函数中,会调用了一个_init()初始化的方法,进行初始化的操作。
function Vue(options){
......
this._init(options)
}
第二步
在_init()初始化函数中,会进行一系列的初始化的操作,包括生命周期的回调。理解这个过程可以更好地理解,生命周期钩子是什么时候回调,我们需要在什么时间段使用生命周期钩子。 首先会处理
1.首先会检测组件的名字是否合格,限制组件的名字必须由普通字符和“-”组成的,且必须以字母开头。
2.判断是否是组件,如果是组件的话,会对组件的options进行处理,将层级比较深的属性放在$options中,减少了查找时的消耗。
if (options && options._isComponent) {
initInternalComponent(vm, options)//是组件的话走这步,优化options
} else { // 合并vue属性
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
3.如果是根组件的话,那么就会合并options。在合并的过程中,会规范化,inject、directives,props等,因为这三项的写法有多种形式,所以我们需要将他们的格式统一进行合并。
inject:['foo'],inject:{bar:'foo'} ==> inject:{foo:{from: 'foo' }}
props:['size','number'],props:{height:{type:number}} ==>props: { size: { type: null },
myMessage: { type: null } },props: { height: { type: Number } }
4.混入合并
5.返回一个全新的options
第三步
在_init()初始化函数中,会进行一系列的初始化操作,如生命周期,事件等经常出现在vue官网中生命周期的那张图中。
// 初始化组件生命周期标志位
initLifecycle(vm)
// 初始化组件事件侦听
initEvents(vm)
// 初始化渲染方法
initRender(vm)
callHook(vm, 'beforeCreate')
// 初始化依赖注入内容,在初始化data、props之前
initInjections(vm) // resolve injections before data/props
// 初始化props/data/method/watch/methods
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
按顺序来讲的话就是
-
初始化生命周期标志位 作用:初始化生命周期的目的是建立出组件之间的关系,在实例对象上赋值$parent,$children等
-
初始化事件监听 作用:处理自定义事件,比如,父组件在子组件上自定义了监听事件,子组件会处理这个监听事件转换成this.$emit(...),this.$on(...),也就是说是子组件在监听。
-
初始化渲染方法 作用:待定....后续更新
-
生命周期钩子函数“beforeCreate”回调 作用:作为一个回调函数可供开发者使用
-
初始化injects在初始化数据之前 作用:对inject做初始化操作,简述大致流程。首先会获取inject的key转换成一个数组,然后遍历key的数组,在每一次的遍历中,都会根据组件之间的父子关系($parent,上文初始化生命周期标志位的时候,已经建立了这些连接)向上查找父组件的provide的值也就是。vm._provide的值,如果找到了,就会将值保存下来,如果没有找到,那么就会使用inject所设置的默认值。然后将数据设置为响应式的。
6.初始化数据state,包括data,methods,props,computed和watch 作用:将数据设置为响应式的(后续文章详细讲解)
-
初始化provide 作用:将组建上provide的值,设置到vm._provide上,目的是让inject向上查找可以找到
-
生命周期钩子函数“created” 作用:作为一个回调函数可供开发者使用,此时可以访问到数据。
第四步
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
最后一步就是判断options中是否有el,如果有el就会自动调用$mount函数挂载到el上,如果没有el,那么就需要手动调用$mount函数进行挂载。
注意
initinject先于initprovide
我们知道inject是向上寻找父组件的_provide属性的,但是inject的初始化操作确实在provide之前的,这可能造成一些疑问,实际上子组件是在父组件的$mount中进行渲染的,这个时候父组件的_provide早就准备好了,随时可以访问的。
initinject先于initSatte
实际上这样做的目的是让data中的数据可以访问可以依赖inject中获取的数据。
总结
1.在vue构造函数中调用_init函数
2.在_init函数中,首先会判断是不是根组件,如果不是根组件,就会将options扁平化,存在$options中,这样在查找的时候,会节省很多时间。如果是根组件,就会合并options,比如全局注册自定义指令,全局设置组件等。在合并options的时候会进行规范化的操作,然后是混入合并,返回新的options
3.initLifecycle进行生命周期标志位初始化,搞定组件之间的关系
4.initEvents处理自定义事件
5.initRender初始化渲染方法
6.生命周期"beforeCreate"函数回调
7.initInjections初始化inject
8.initState初始化数据,实现数据响应式
9.initProvide 初始化provide,供子组件的inject向上查找
10.生命周期"created"进行回调
11.判断options是否有el,然后决定是否自动调用$mount
这就是new Vue的初始化过程。