优秀的编程知识分享平台

网站首页 > 技术文章 正文

「 原创 」Vue 源码解析 - new Vue() 之后发生了什么?

nanyue 2024-09-06 20:23:20 技术文章 7 ℃

《「 原创 」Vue源码解析 - Vue究竟是什么?》中知晓了 Vue 实际上就是一个 function,该方法的内容也很简单,就是调用了 _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)
}

在 /src/cor/instance/init.js,定义了 _init 原型方法

export function initMixin (Vue: Class<Component>) {
  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)
    }
  }
}

初始化阶段,主要做了:

合并配置

初始化代理

初始化生命周期

初始化事件

初始化渲染

触发 beforeCreate 钩子

初始化注入器

初始化 data / props / computed / watcher 等

初始化提供者

触发 created 钩子

完成初始化,$options 中存在 el 属性的话,则开始执行实例挂载

小结

new Vue() 之后要干的大事件,都罗列在上面了,非常清晰,具体实现都分到各个功能 / 模块中去了,init 只是集中去调用 / 管理而已。

beforeCreate / created 钩子也是在这里面触发的,需要注意的是 beforeCreate 钩子触发时,initState() 并未执行,也就是说 data / props / computed / watcher 等都还没有初始化,所以并不适合在 beforeCreate 钩子函数内有数据交互的动作,适合做一些 loading 状态。在 created 中就可以对数据进行操作了,我们的异步请求也可以放在这个钩子函数内处理。

接下来就要针对上述事件进行逐个深入分析,在分析过程中可以带着“这些事件是干什么的?”,“在这些事件的实现原理是什么?”,“从原理中窥探作者思想,有哪些是值得借鉴的?”,要形成自己的思考才是最终的目的。

最近发表
标签列表