返回

Vue 源码剖析:揭秘 Vue 实例挂载全过程

前端

当我们使用 Vue 时,总是会创建一个 Vue 实例,那么在创建 Vue 实例时,内部发生了什么?我们今天就来窥探 Vue 源码,看看 Vue 是如何实现实例挂载的。

从 new Vue 对象开始

const vm = new Vue({
  el: '#app',
  data: {
    message: 'Hello, Vue!'
  }
})

当我们通过 new Vue({}) 创建一个 Vue 实例时,首先会调用 Vue 的构造函数。但是,Vue 的构造函数只做了一件事情,就是调用 _init 函数进行初始化。

_init,初始化

_init (options?: Object) {
  // Vue.prototype._init 是一个中间层,调用_initOptions传入options
  this._initOptions(options)
  // 初始化各种属性
  this._initScope()
  this._initEvents()
  // 真正对实例进行观测依赖的函数入口
  this._initObservable()
  // 对组件进行挂载挂载
  this._initDOMHooks()
}

_init 函数做了很多事情,包括:

  1. 调用 _initOptions 函数,将用户传入的选项与默认选项合并,形成最终的选项。
  2. 初始化各种属性,如 $el$data$props 等。
  3. 初始化事件系统。
  4. 调用 _initObservable 函数,对实例进行观测依赖的处理。
  5. 调用 _initDOMHooks 函数,对组件进行挂载挂载。

_initDOMHooks,组件挂载

_initDOMHooks (mounted: Function) {
  // this.$el 是真实dom节点
  // Vue.compile 是一个全局的渲染函数
  this.$el = typeof this.$el === 'string' ? query(this.$el) : this.$el
  this._callHook('beforeMount')
  // 真正的挂载方法,将虚拟dom挂载到真实dom
  this._mount(this.$el, mounted)
  this._callHook('mounted')
}

_initDOMHooks 函数主要做了以下几件事:

  1. $el 属性的值转换为真实 DOM 节点。
  2. 调用 beforeMount 钩子函数。
  3. 调用 _mount 函数,将虚拟 DOM 挂载到真实 DOM。
  4. 调用 mounted 钩子函数。

_mount,虚拟 DOM 挂载

_mount (el: Node | Element, hydrating?: boolean): Component {
  // 调用 `_render` 函数生成虚拟dom,虚拟dom就是渲染函数的返回结果
  this._vnode = this._render()
  // 虚拟dom挂载的入口
  this._update(this._vnode, el, hydrating)
}

_mount 函数主要做了以下几件事:

  1. 调用 _render 函数生成虚拟 DOM。
  2. 调用 _update 函数,将虚拟 DOM 挂载到真实 DOM。

总结

以上就是 Vue 实例挂载的全过程。通过剖析 Vue 源码,我们了解到 Vue 是如何将虚拟 DOM 挂载到真实 DOM 的。