vue2 源码分析 大致流程图

302 阅读4分钟

出发点:在new Vue()方法,会调用_init()方法,那么这个方法在什么时候被定义的?

src/core/instance/index.js文件中,定义了Vue构造函数和一些mixin方法。通过打断点调试。

先执行initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue) renderMixin(Vue)等方法,那么我们先从此地方研究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'

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

先执行initMixin/stateMixin/eventsMixin/lifecycleMixin/renderMixin 方法 -- 主要定义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)
  }

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

  export default Vue
  1. initMixin(Vue):主要定义Vue.prototype._init
  2. stateMixin(Vue):定义一些state相关的方法 data/data / props /set/set/delete/$watch
  3. eventsMixin(Vue):定义和事件相关的方法 onon,off,emitemit,once
  4. lifecycleMixin(Vue):定义生命周期的更新和销毁的方法 _update,forceUpdateforceUpdate ,destroy
  5. renderMixin(Vue):定义 $nextTick,_render;还通过installRenderHelpers方法定义了一些和渲染函数相关的方法 比如:_v
export function installRenderHelpers (target: any) {
  target._o = markOnce
  target._n = toNumber
  target._s = toString
  target._l = renderList
  target._t = renderSlot
  target._q = looseEqual
  target._i = looseIndexOf
  target._m = renderStatic
  target._f = resolveFilter
  target._k = checkKeyCodes
  target._b = bindObjectProps
  target._v = createTextVNode
  target._e = createEmptyVNode
  target._u = resolveScopedSlots
  target._g = bindObjectListeners
  target._d = bindDynamicKeys
  target._p = prependModifier
}

initGlobalAPI 方法

此方法是定义了Vue全局方法 在new Vue 之前执行

export function initGlobalAPI (Vue: GlobalAPI) {
  // config
  const configDef = {}
  configDef.get = () => config
  Object.defineProperty(Vue, 'config', configDef)

 
  //exposed util methods.
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }

  Vue.set = set
  Vue.delete = del
  Vue.nextTick = nextTick

  // 2.6 新增的api --使对象为响应式  -- 使用这个代替Vuex
  Vue.observable = <T>(obj: T): T => {
    observe(obj)
    return obj
  }

  /*
  设置
  Vue.options.components={
  }
  Vue.options.directives={
  }
  Vue.options.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
  // 扩展Vue 就是注册 全局组件KeepAlive是abstract组件,还有三个钩子(created/destroyed/mounted)  
  extend(Vue.options.components, builtInComponents)
  
  //定义Vue.extend方法
  initUse(Vue)
  //定义Vue.mixin
  initMixin(Vue)
  //定义Vue.extend
  initExtend(Vue)
  
  //定义 Vue.component/Vue.directive/Vue.filter 方法  
  //根据definition判断是获取还是注册操作
  // Vue.component 就是执行Vue.extend
  //
  initAssetRegisters(Vue)
}

// 注册Vue.component/Vue.directive/Vue.filter 全局方法
export function initAssetRegisters (Vue: GlobalAPI) {
  /**
   * Create asset registration methods.
   */
  ASSET_TYPES.forEach(type => {
    Vue[type] = function (
      id: string,
      definition: Function | Object
    ): Function | Object | void {
      if (!definition) {//获取操作
        return this.options[type + 's'][id]
      } else {//注册操作
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production' && type === 'component') {
          validateComponentName(id)
        }
        if (type === 'component' && isPlainObject(definition)) {
          definition.name = definition.name || id
          //this.options._base 就是Vue
          definition = this.options._base.extend(definition)
        }
        if (type === 'directive' && typeof definition === 'function') {
          definition = { bind: definition, update: definition }
        }
        this.options[type + 's'][id] = definition
        return definition
      }
    }
  })
  /** Class 继承
   * Class inheritance
   就是生成 VueComponent
   返回VueComponent构造函数
   options 就是extendOptions 和 Vue的options 合并的结构
   superOptions 指向super的options
   
   */
  Vue.extend = function (extendOptions: Object): Function {
    extendOptions = extendOptions || {}
    const Super = this  //Vue  每个Vue都有cid
    const SuperId = Super.cid 
    
    // 配置项的_Ctor 如果不存在 创建并赋值{}
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    //缓存
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }

    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
      validateComponentName(name)
    }

    const Sub = function VueComponent (options) {
      this._init(options)
    }
    
    //继承
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    
    //合并options 
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    
    //定义super 指向Vue
    Sub['super'] = Super

    // For props and computed properties, we define the proxy getters on
    // the Vue instances at extension time, on the extended prototype. This
    // avoids Object.defineProperty calls for each instance created.
    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    // allow further extension/mixin/plugin usage
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

    // create asset registers, so extended classes
    // can have their private assets too.
    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    // enable recursive self-lookup
    if (name) {
      Sub.options.components[name] = Sub
    }

    // keep a reference to the super options at extension time.
    // later at instantiation we can check if Super's options have
    // been updated.
    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)

    // cache constructor
    cachedCtors[SuperId] = Sub
    return Sub
  }
}
  • Vue.extend(options);
    1. options | Object
    2. 是利用了Vue构造器 创建一个子类-VueComponent
    3. 返回VueComponent 构造函数
    4. use/component/directive/filter/extend/mixin/super --指向Vue
    5. options/extendOptions/superOptions
    6. new的时候执行_init()方法 就是Vue构造函数的_init()方法
       const Sub = function VueComponent (options) {
         this._init(options) //this -> super
      }
      

initGlobalAPI:

  • Vue的全局Api:
    1. config

    2. util

    3. set

    4. delete

    5. nextTick

    6. observable(2.6新增)

    7. Vue.options.components,Vue.options.directives,Vue.options.filters 创建空对象

    8. use

    9. mixin

    10. extend

    11. 定义Vue.component的方法

    12. 定义Vue.directive的方法

    13. 定义Vue.filter 的方法 Vue.component/Vue.directive/Vue.filter 判断definition 是否传递(第二个参数),如果传递了第二个参数就直接返回(就是获取操作)this.options.components,this.options.directives,this.options.filters [id] 获取; 就是全局组件/指令/过滤器 全部放在 this.options 内部

    14. version

    15. cid

创建不同平台的patch函数

进入html页面开始执行代码

  • 执行代码
 Vue.component('comp',{
     template:'<div>i am comp</div>'
 })
  • 调用Vue.component方法 返回 VueComponent构造函数 并且挂在this.options.components内,此项就是挂载全局组件的。

    • 其实就是执行extend()方法,将definition 配置项转化成构造函数;

  • 再执行new Vue方法;
  const app=new Vue({            
      el:'#app',
      data:{
          foo:1
      }            
  });

其实就是执行_init方法 (Vue.prototype_init)

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方法内部

    1. 合并 options --> 全局的和new Vue()时传人的options{el:'#app',data:{foo:1}}
    2. 一系列初始化操作
      initLifecycle(vm)  -- 定义实例vm的 $parent /$root / 
      $children/$refs 等属性 初始化工作
      initEvents(vm) --  定义实例 _events={}
      initRender(vm) -- 定义实例的 $slots / $scopedSlots /_c / $createElement /定义$attrs/$listeners 响应式属性
      
    

    export function initEvents (vm: Component) {
      vm._events = Object.create(null)
      vm._hasHookEvent = false
      // init parent attached events
      const listeners = vm.$options._parentListeners
      if (listeners) {
        updateComponentListeners(vm, listeners)
      }
    }
    
![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f3cf9378d7d94f369e9698e89bdb6764~tplv-k3u1fbpfcp-watermark.image)

```js
vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )

整体流程图