Vue实例挂载的过程中发生了什么?

59 阅读3分钟

Vue实例的挂载过程是其生命周期中的关键环节,它完成了Vue应用从数据到视图的转换。为了让你快速把握全局,下图直观地展示了这一过程的核心阶段与关键步骤:

image.png

flowchart TD
    A[创建Vue实例] --> B[初始化阶段<br>initLifecycle/initEvents等]
    B --> C[调用 beforeCreate 钩子]
    C --> D[初始化数据响应式<br>initState]
    D --> E[调用 created 钩子]
    E --> F{检查 el 选项}
    F -->|存在| G[编译模板为渲染函数]
    F -->|不存在| H[等待手动调用 $mount]
    H --> G
    G --> I[调用 beforeMount 钩子]
    I --> J[创建Watcher并执行首次渲染]
    J --> K[生成虚拟DOM并转为真实DOM]
    K --> L[调用 mounted 钩子]
    L --> M[进入响应式更新周期]

下面我们来详细解读图中的每一个关键阶段。

🔧 初始化阶段

当你执行 new Vue(options)时,Vue 内部会启动初始化流程:

  • ​核心属性初始化​​:Vue 会初始化实例的生命周期、事件系统以及渲染函数相关的属性和方法(如 $parent, $children, $slots等)。
  • ​调用 beforeCreate钩子​​:此时,实例的数据观测(data)和事件配置都尚未初始化,因此你无法在此钩子中访问 datacomputedmethods中的数据和方法。
  • ​初始化依赖注入与响应式数据​​:接着,Vue 会处理 provide/inject选项,并进入响应式系统的核心环节——调用 initState函数。这个函数会依次初始化 propsmethodsdatacomputedwatcher,其中 data的属性会被转换为 ​​getter/setter​​,从而为后续的依赖收集和触发更新奠定基础。
  • ​调用 created钩子​​:至此,实例的数据观测已完成,你可以安全地访问 datacomputed等响应式数据。此时,​​DOM 还未生成​​,所以无法进行 DOM 操作。这个钩子常用于发起异步数据请求。

📦 模板编译与挂载准备

初始化完成后,如果配置中提供了 el选项,实例会自动进入挂载阶段;如果没有,则需要等待手动调用 vm.$mount()方法。

  • ​模板编译​​:Vue 会检查是否提供了 render函数。如果没有,则会查找 template选项或 el选项所指元素的 outerHTML 作为模板。接着,​​编译器会将模板编译成渲染函数​​。这个过程包括将 HTML 模板解析成抽象语法树(AST),优化 AST,最终生成可执行的 render函数。
  • ​调用 beforeMount钩子​​:在挂载开始之前,此钩子被触发。此时,render函数已准备就绪,但尚未将虚拟 DOM 渲染成真实 DOM 并替换掉 el指向的挂载点。

⚡ 渲染、挂载与更新

这是将虚拟DOM转化为真实DOM并插入页面的核心阶段。

  • ​执行渲染与挂载​​:Vue 会执行上一步得到的 render函数,​​生成虚拟 DOM 树​​。然后,通过 patch算法将虚拟 DOM 转换为​​真实 DOM 节点​​,并​​替换或插入到指定的挂载点​​(el选项对应的 DOM 元素)。同时,会创建一个​​渲染 Watcher​​,用于监听响应式数据的变化,以便未来触发更新。
  • ​调用 mounted钩子​​:挂载完成后,mounted钩子被调用。此时,Vue 实例已被​​完全挂载到 DOM 上​​,你可以操作和访问渲染后的 DOM 元素。但请注意,这并不保证所有子组件也都已被挂载,如需等待整个视图渲染完成,可以在 mounted中使用 this.$nextTick
  • ​进入响应式更新周期​​:挂载完成后,应用进入活跃状态。每当响应式数据发生变化时,渲染 Watcher 会被通知,从而触发​​重新渲染​​。这个过程会生成新的虚拟 DOM 树,并与旧的虚拟 DOM 树进行 ​​Diff 算法对比​​,找出最小差异,然后​​高效地更新真实 DOM​​。在更新前后,会分别触发 beforeUpdateupdated生命周期钩子。

💡 核心机制与注意事项

理解Vue实例挂载过程,还需要把握以下几点:

  • ​响应式系统是核心​​:Vue 通过​​数据劫持​​(Vue 2 使用 Object.defineProperty,Vue 3 使用 Proxy)建立数据与视图的关联。每个组件实例对应一个渲染 Watcher,在数据获取时收集依赖,在数据修改时触发更新。
  • ​虚拟DOM提升性能​​:Vue 引入虚拟 DOM 作为真实 DOM 的轻量级抽象。通过 Diff 算法计算最小变更,再统一更新真实 DOM,有效减少了直接操作 DOM 的性能开销。
  • ​挂载点的选择​​:挂载点(如 #app)在 Vue 实例挂载后,其原有的内容会被 Vue 生成的 DOM 所替换。确保挂载点存在且唯一,避免重复挂载。

希望这份分步详解能帮助你清晰地理解 Vue 实例挂载的完整过程。如果你对某个特定环节,比如响应式原理的细节或 Diff 算法的具体策略有进一步的兴趣,我们可以继续探讨。