/src/core/instance/index.js. //vue初始化,也就是vue构造函数的位置
- import {initMixin} from './init'
- //vue 构造函数
- function Vue(options){
- if (!(this instanceof Vue)) {
- warn$2('Vue is a constructor and should be called with the `new` keyword');
- }
- //调用Vue.prototype._init 方法,该方法是在initMinin中定义的
- this._init(options);
- }
-
- // 定义Vue.prototype._init方法
- initMixin(Vue)
-
- export default Vue
-
/src/core/instance/init.js
- /**
- *定义Vue.prototype._init 方法
- *@param{*} Vue构造函数
- */
- var uid=0
- export function initMixin(Vue: Class
){ - //负责 Vue的初始化过程
- Vue.prototype._init=function(options?:Object){
- // vue实例
- const vm: Component = this
- // 每个vue实例都有一个_uid,并且是依次递增的
- vm.uid = uid++
-
-
- vm._isVue = true
- //处理组件配置项
- if(options && options_isComponent){
-
- /**
- *每个子组件初始化时走这里,这里只做了一些性能优化
- *将组件配置对象上的一些深层次属性放到vm.$options 选项中,以提高代码的执行效率
- */
- initInternalComponent(vm, options)
- }else{
- /**
- *初始化根组件时走这里,合并Vue的全局配置到根组件的局部配置,比如Vue.component 注册的全局组件会合并到根实例的components选项中
- *至于每个子组件的选项合并则发生在两个地方:
- * 1.Vue.component 方法注册的全局组件在注册时做了选项合并
- * 2.{component:{xx}}方式注册的局部组件在执行编译器生成的render函数时选项合并,包括根组件中的components配置
- */
- vm.$options=mergeOptions(
- resolveConstructorOptions(vm.constructor),options || {}, vm)
- )
- }
- /* istanbul ignore else */
- if(process.env.NODE_ENV !== 'production'){
-
- //设置代理,将vm实例上的属性代理到vm._renderProxy
- initProxy(vm)
-
- }else{
- vm._renderProxy = vm
- }
- //expose real self
- vm._self = vm
- //初始化组件实例关系属性,比如$parent、$children、$root、$refs等
- initLifecycle(vm)
- /**
- *初始化自定义事件,这里需要注意一点,所有我们在
@click ='handleClick'/>上注册的事件,监听者不是父组件,而是子组件本身,也就是说事件的派发和监听者都是组件本身,和父组件无关 - */
- initEvents(vm)
- //解析组件的插槽信息,得到vm.$slot,处理渲染函数,得到vm$createElement方法,即h函数
- initRender(vm)
- //调用beforeCreate 钩子函数
- callHook(vm,'beforeCreate')
- //初始化组件的inject配置项,得到result[key]=val 形式的配置对象,然后对结果数据进行响应式处理,并代理每个key
- initInjections(vm)
- //数据响应式的重点,处理props,methods,data.computed,watch
- initState(vm)
- //解析组件配置项上的provide对象,将其挂载到vm._provided属性上
- initProvide(vm)
- //调用created钩子函数
- callHook(vm,'created')
- //如果发现配置项上有el选项,则自动调用 $mount 方法,也就是说有了el选项,就不需要再手动调用$mount,反之,没有el则必须手动调用$mount
- if(vm.$options.el){
- //调用$mount方法,进入挂载阶段
- vm.$mount(vm.$options.el)
- }
- }
- }
/src/core/instance/init.js
- /**
- * 从组件构造函数中解析配置对象options,并合并基类选项
- * @param {*} Ctor
- * @returns
- */
- export function resolveConstructorOptions (Ctor: Class<Component>){
- //配置项目,获取Vue上面绑定的属性
- let options = Ctor.options
- if(Ctor.super){
- //存在基类,递归解析基类构造函数的选项
- const superOptions = resolveConstructorOptions(Ctor.super)
- const cachedSuperOptions = Ctor.superOptions
- if(superOptions !== cachedSuperOptions){
-
- //说明基类构造函数选项已经发生改变,需要重新设置
- Ctor.superOptions = superOptions
- //检查Ctor.superOptions上是否有任何后期修改/附件的选项
- const modifiedOptions = resolveModifiedOptions(Ctor)
- // 如果存在被修改或增加的选项,则合并两个选项
- if(modifiedOptions){
-
- extend(Ctor.extendOptions,modifiedOptions);
- }
- //选项合并,将合并结果赋值为Ctor.options
- options = Ctor.options = mergeOptions(superOptions,Ctor.extendOptions)
- if(options.name){
- //该组件构造函数的name为自身的组件构造函数时自己的constructor
- options.components[options.name] = Ctor
- }
- }
- }
- return options
- }
/src/core/instance/init.js
- /**
- * 解析构造函数选项中后续被修改或者增加的选项
- */
- function resolveModifiedOptions (Ctor: Class<Component>): ?Object{
- let modified;
- //构造函数选项
- const lastest = Ctor.options
- //密封的构造函数选项,备份
- const sealed = Ctor.sealedOptions
- //对比两个选项,记录不一致的选项
- for(const key in latest){
- if(latest[key] !== sealed[key]{
-
- if(!modified) modified={}
- modified[key]=latest[key]
- }
- }
- return modified
- }
/src/core/util/options.js
- /**
- * 合并两个选项,出现相同配置项时,子选项会覆盖父选项的配置
- */
- export function mergeOptions(
- parent: Object,
- child: Object,
- vm?: Component
- ):Object {
- if(process.env.NODE_ENV !== 'production'){
- checkComponents(child)
- }
- if(typeof child === 'function'){
- child = child.options
- }
- // 标准化props、inject、directive选项,方便后续程序的处理
- normalizeProps(child ,vm)
- normalizeInject(child ,vm)
- normalizeDirectives(child)
- //处理原始child对象上的extends和mixins,分别执行mergeOptions.将这些继承而来的选项合并到parent
- //mergeOptions 处理过的对象会含有_base属性
- if(!child._base){
- if(child.extends){
- parent = mergeOptions(parent, child.extends, vm)
- }
- if(child.mixins){
- for(let i=0,l = child.mixins.length; i < l; i++){
- parent = mergeOptions(parent, child.mixins[i],vm)
- }
- }
- }
- const options = {}
- let key
- //遍历 父选项
- for (key in parent){
- mergeField(key)
- }
- //遍历子选项,如果父选项不存在该配置,则合并,否则跳过,因为父子拥有同一个属性的情况在上面处理父选项时已经处理过了,用的子选项的值;
- for(key in child){
- if(!hasOwn(parent,key){
- mergeField(key)
- }
- }
- function mergeField(key){
- // strats = Object.create(null)
- const strat = strats[key] || defaultStrat
- // 值如果为childVal 存在则优先使用childVal,否则使用parentVal
- options[key] = strat(parent[key],child[key],vm,key)
- }
-
- return options
- }
/src/core/instance/inject.js
- /**
- *初始化inject配置项
- * 1.得到 result[key]=val
- * 2.对结果数据进行响应式处理,代理每个key到vm实例
- */
- export function initInjections (vm:Component){
- //解析inject配置项,然后从祖代组件的配置中找到 配置项中每一个key对应的val,最后得到 result[key]=val的结果
- const result=resolveInject(vm.$options.inject,vm)
- //对 result做数据响应式处理,也有代理inject配置中每个key到vm实例的作用
- //不建议在子组件去更改这些数据,因为一旦祖代组件中 注入的provide发生更改,你在组件中做的更改就会被覆盖
- if(result){
-
- toggleObserving(false)
- Object.keys(result).forEach(key=>{
- /* istanbul ignore else */
- if(process.env.NODE_ENV !== 'production'){
-
- defineReactive(vm,key,result[key],()=>{
- warn(
- `Avoid mutating an injected value directly since the changes will be ` +`overwritten whenever the provided component re-renders. ` + `injection being mutated: "${key}"`,
- vm)
- })
- }else{
- defineReactive(vm,key,result[key]
- }
- })
- toggleObserving(true)
- }
-
- }
/src/core/instance/inject.js
- /**
- *解析 inject配置项,从祖代组件的provide配置中找到key对应的值,否则用默认值,最后得到result[key]=val
- *inject 对象肯定是以下这个结构,因为在合并选项时对组件配置对象做了标准化处理
- *@param{*}inject={
- * key:{
- * from:provideKey,
- * default:xx
- * }
- *}
- */
- export function resolveInject(inject:any,vm:Component): ?Object{
- if(inject){
- const result=Object.create(null)
- //inject 配置项的所有key
- const keys = hasSymbol ? Reflect.ownKeys(inject):Object.keys(inject)
-
- //遍历key
- for(let i=0;i
length;i++){ - const key=keys[i]
- //跳过__ob__对象
- if(key === '__ob__') continue
- //拿到provide中对应的key
- const provideKey=inject[key].from
- let source = vm
- //遍历所有的祖代组件,直到根组件,找到provide中对应的key的值,最后得到result[key]=provide[provideKey]
- while(source){
- if(source._provided && hasOwn(source._provided,provideKey)){
- result[key] = source._provided[provideKey)
- break
- }
- source = source.$parent
- }
- //如果上一个循环未找到,则采用inject[key].default,如果没有设置default值,则抛出错误
- if(!source){
-
- if('default' in inject[key]){
- const provideDefault = inject[key].default
- result[key] = typeof provideDefault === 'function' ? provideDefault.call(vm) : provideDefault
- }else if(process.env.NODE_ENV !== 'production'){
- warn(`Injection "${key}" not found`,vm)
- }
- }
- }
- return result
-
- }
-
-
- }
/src/core/instance/inject.js
- /**
- *解析组件配置项上的provide对象,将其挂载到vm._provided属性上
- */
- export function initProvide (vm: Component){
- const provide = vm.$options.provide
- if(provide){
- vm._provided = typeof provide === 'function' ? provide.call(vm):provide
- }
- }
Vue的初始化过程(new Vue(options))都做了什么?