vue源码学习(一)

158 阅读2分钟

介绍:主要记录自己学习源码的整个历程;源码学习较晚,所以本次主要针对2.xx版本,如有理解不到位的地方,欢迎讨论(随着知识的增加,会不断修改、完善当前文章)

1.要想学习源码,个人觉得要知道vue的整体流程是什么,宏观的了解每一步是做什么的,然后再了解每一步是怎么实现的。

Vue主干流程

1.new Vue (合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher)

当 new Vue(options) 时调用的是 src/core/instance/index.js 文件中的Vue函数,源码如下:

import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'
//new 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) //init方法在哪???-----竟然是initMixin初始化的时候,声明了_init
}

initMixin(Vue)   //分支流程吗?
stateMixin(Vue)  //分支流程吗?
eventsMixin(Vue) //分支流程吗?
lifecycleMixin(Vue) //分支流程吗?
renderMixin(Vue)  //分支流程吗?

export default Vue

可以看到在初始化后又调用了 this._init(options) 方法,该方法其实在 src/core/instance/init.js 中,源码如下:

export function initMixin (Vue: Class<Component>) {   //----------竟然是initMixin
  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          //看名字,根据vue官方文档猜方法用途
    initLifecycle(vm)     //看名字,感觉是:初始化生命周期
    initEvents(vm)        //看名字,感觉是:初始化事件
    initRender(vm)        //看名字,感觉是:初始化渲染
    callHook(vm, 'beforeCreate') //看名字,跟生命周期有关
    //以下是个人找的相关资料,加的注解
    //provide/inject,这个是Vue在2.2.0版本新增的一个属性,按照Vue官网的说法,它的作用是:
    //这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,
    //并在起上下游关系成立的时间里始终生效。
    //---------------------------这解释,真是。。。,还好有代码---------------------------------
    // 父级组件提供 'foo'
    //  var Provider = {
    //    provide: {
    //      foo: 'bar'
    //    },
      // ...
    //   }

    // 子组件注入 'foo'
    //  var Child = {
    //     inject: ['foo'],
    //     created () {
    //     console.log(this.foo) // => "bar"
    //   }
       // ...
    //  }
    //看到这里,大概知道provide/inject是干什么的了
    initInjections(vm) // resolve injections before data/props
    initState(vm)      //看到上下给的英文注解,明白这里是,初始化data/props
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')  //看名字,跟生命周期有关-----beforeCreate与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. options 为 new Vue(options) 时传入的选项,并通过 mergeOptions 方法把 options 合并到 vm.$options 中。
  2. 调用 initLifecycle(vm)initEvents(vm)initRender(vm)initState(vm) 函数进行生命周期的初始化、事件中心的初始化、渲染的初始化、data props computed watcher的初始化等等。
  3. 调用 vm.$mount(vm.$options.el) 进行挂载渲染成真实dom。

总结: 首先 new Vue(opt);经历了什么?

this._init(options) //执行了它

_init(options) // 内部包含了:调用 initLifecycle(vm)initEvents(vm)、 //initRender(vm)initState(vm) 函数进行生命周期的初始化、事件中心的初始化 //、渲染的初始化、data props computed watcher的初始化等等。

让我们欣赏一下官网给我们的图片:

2018072510403420.png

疑问:mounted这些生命周期去哪了?从刚刚的源码中并未体现