Vue的初始化过程都做了什么?

Vue的初始化过程都做了什么?

从构造函数前面打断点,然后进行一步步的调试:
调试方式
首先会进入init.js里面执行Vue构造函数。init函数之前会进行一下判断:即init之前的代码作用为:检测在使用 Vue 构造函数时是否使用了 new 关键字进行实例化。它主要用于开发环境下的警告提示,之后开始执行init函数正式进入Vue初始化过程。这个options就是用户传入的合并选项在这里,即

{data:{msg:'123'},
methods:{
eat(){console.log('eat')},
drink(){console.log('drink')}}}

在这里插入图片描述
下面让我们进入init方法,给出具体的源代码:rt

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)
    }
  }
}

这个方法是vue实例的初始化方法,它会在创建一个 Vue 实例时被调用。让我们来进一步展开这个方法具体做了什么。

  1. 首先,给当前实例设置 _uid 属性,用于标识唯一的 Vue 实例。
  2. 创建变量startTag 和 endTag 是用于标记解析模板中的标签的起始和结束位置的变量。这是为了创建ast语法树用的,然后设置实例的 _isVue 属性为 true,表示该对象是一个 Vue 实例。
  3. 判断该组件是不是内部组件,如果是内部组件则调用initInternalComponent(vm, options)进行组件合并,否则调用mergeOptions进行组件合并,至于为什么这么做,就是为了提高性能,下面是详细的介绍:

当创建一个组件实例时,会调用 _init 方法进行初始化。在初始化过程中,会检查 options 对象是否存在且具有 _isComponent 属性。如果存在,并且 _isComponent 的值为 true,则表示当前组件是一个内部组件(可以想象成局部注册的组件)。
针对内部组件的实例化,由于内部组件的选项合并不需要特殊处理,而且动态选项合并的性能较低,因此可以进行优化。在这种情况下,会调用 initInternalComponent 方法,将内部组件实例和选项对象作为参数传递给该方法。
initInternalComponent 方法负责完成内部组件的初始化,包括对选项的处理、状态的初始化等。通过将内部组件的初始化逻辑单独提取为一个方法,可以提高内部组件实例化的性能,并避免对内部组件的选项进行不必要的处理。
总而言之,上述代码片段中的逻辑用于优化内部组件的实例化过程,通过调用 initInternalComponent 方法进行内部组件的初始化。这样可以提高内部组件实例化的性能,并简化内部组件选项的处理过程。

下面是处理内部组件合并的源代码:

export function initInternalComponent (vm: Component, options: InternalComponentOptions) {
  const opts = vm.$options = Object.create(vm.constructor.options)
  // doing this because it's faster than dynamic enumeration.
  const parentVnode = options._parentVnode
  opts.parent = options.parent
  opts._parentVnode = parentVnode

  const vnodeComponentOptions = parentVnode.componentOptions
  opts.propsData = vnodeComponentOptions.propsData
  opts._parentListeners = vnodeComponentOptions.listeners
  opts._renderChildren = vnodeComponentOptions.children
  opts._componentTag = vnodeComponentOptions.tag

  if (options.render) {
    opts.render = options.render
    opts.staticRenderFns = options.staticRenderFns
  }
}

这个函数的意思:子组件的选项会通过合并方式添加到子组件实例的选项中,以便子组件能够继承和访问父组件的选项。通过这种方式,子组件可以访问父组件的属性、方法、生命周期钩子等。
即initInternalComponent 方法主要用于局部注册的组件实例化时的选项合并,mergeOptions 方法用于全局注册和局部注册的组件选项的合并。合并的选项主要为components,directives,methods,computed,props等等,还有子组件的钩子函数等等。合并的结果是父组件的选项优先级高,子组件的选项会被合并到父组件的选项中,形成最终的组件选项对象
4. 接下来执行initLifecycle方法,它的作用就是初始化组件实例的生命周期相关属性:例如:
初始化 $parent 属性:将父组件实例赋值给 $parent,用于在组件实例中可以访问到其父组件实例。
初始化 $root 属性:将根组件实例赋值给 $root,用于在组件实例中可以访问到根组件实例。
初始化 $children 属性,初始化 $refs 属性
初始化 _watcher 属性
初始化 _inactive 属性
初始化 _isMounted 属性:将 false 赋值给 _isMounted,表示组件实例当前没有挂载到 DOM 中。
初始化 _isDestroyed 属性
初始化 _isBeingDestroyed 属性
5. initEvents 方法初始化组件实例的事件相关属性和方法。它主要完成以下几个任务:
初始化 _events 属性:将空对象赋值给 _events,用于存储组件实例的事件监听器。
初始化 _hasHookEvent 属性:将 false 赋值给 _hasHookEvent,表示组件实例当前没有绑定任何钩子函数的事件监听器。
将组件构造函数选项中的事件监听器合并到组件实例的 _events 属性中。这样可以在组件实例中通过 o n 、 on、 onoff、$once 等方法进行事件的订阅和取消订阅。
将组件实例的父组件的事件监听器合并到组件实例的 _events 属性中。这样可以在组件实例中访问到其父组件的事件监听器。
总之,通过执行 initEvents 方法,Vue 组件实例可以进行事件的订阅和触发,从而实现组件间的通信和交互。

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)
  }
}

6.执行initRender 方法,Vue 组件实例具备了渲染功能所需的基本属性和方法(_vnode,$slots等等)。它为组件的模板渲染提供了必要的支持,使组件能够生成对应的虚拟节点,并进行相应的渲染和更新操作。
7.调用beforeCreate钩子函数,注意,beforeCreate 钩子函数在组件实例创建之前执行,此时组件的数据、计算属性、方法等还未初始化,但是可以在这个阶段进行一些初始化配置或执行其他操作。还有就是,选项合并是关于组件选项对象的处理,而初始化是关于组件实例的内部状态的设置和准备。
8.initInjections 方法的主要功能是处理组件实例的注入选项(inject)并将其添加到组件实例的 _provided 属性中。它会在组件实例化的过程中被调用,确保组件实例可以直接访问注入的数据。
9.执行 initState 方法,它的作用是初始化组件实例的状态,状态包括组件的数据(data)、计算属性(computed)、观察者(watchers)等,下面给出代码,按这个顺序进行的初始化:

function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}

10.initProvide方法,用于初始化组件的Provide选项,其允许一个组件向其所有的子组件提供数据或者方法,这样子组件就可以通过inject来访问这些数据和方法。
11…调用created钩子函数.组件实例刚好被创建然后立即调用该方法,表明此时组件的数据观测 和事件机制都已经初始化完成。
12.模板渲染:在 created 钩子函数之后,Vue.js 将根据组件的虚拟 DOM 结构开始渲染组件的模板。这个过程涉及以下步骤:
将组件的虚拟 DOM 与实际的 DOM 进行比对,找出需要更新的部分。
将需要更新的部分进行 DOM 操作,实现视图的更新。
13.调用beforeMount钩子函数
14.模板挂载:在 beforeMount 钩子函数之后,Vue.js 开始将组件的虚拟 DOM 渲染到实际的 DOM 中。这个过程包括以下步骤:
将组件的虚拟 DOM 插入到实际 DOM 中的指定位置。
执行实际的 DOM 操作,如添加、修改或删除 DOM 元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值