vue基础进阶(十二): Vue中模版的编译过程

135 阅读3分钟

Vue中模版的编译是如下过程:模版--->ast(抽象树)-->render 函数->虚拟 dom->实际 dom。

vue中的模版通过 compiler 编译成ast(用于表示模版的 js 对象,也可以说ast就是一个用来表示源代码的js对象),然后将ast生成对应render函数(这里先不谈关于ast的转化细节),render函数然后生成虚拟节点 vnode(用来描述节点及其子节点的信息),vnode的集合组成Virtual Dom(vue组件建立起来的整个vnode树叫虚拟Dom树),最后生成真实Dom。

非常好的问题!Vue 和 React 其实都涉及“模板到真实 DOM”的过程,但它们的内部机制、设计思路有所不同。下面用清晰、通俗+源码原理的方式,帮你梳理 Vue 从模板到真实 DOM 的完整过程,以及模板编译的原理


一、Vue 模板到真实 DOM 的整体流程

1. 模板写法(.vue 或 template 字符串)

<template>
  <div class="msg">{{ message }}</div>
</template>

2. “编译”阶段:模板变成渲染函数(render function)

2.1 模板编译器

  • Vue 在构建阶段,会用自己的模板编译器vue-template-compiler)把 HTML 模板编译为“渲染函数”。
  • 这个过程发生在 Vue Loader(SFC单文件组件)构建时,或浏览器运行时(直接 template 写在页面上)。

2.2 编译过程分为三步

  • 解析(Parse):把模板字符串解析为 AST(抽象语法树对象)。
  • 优化(Optimize):标记静态节点,便于后续 patch 阶段跳过静态内容。
  • 生成 Codegen:把 AST 生成 render 函数(JavaScript 代码)。

简例(原理): 模板:

<div>{{ msg }}</div>

最终编译为:

render = function() {
  // _c 创建元素,_v 创建文本,_s 变量取值
  return _c('div', [_v(_s(this.msg))])
}

Vue 3 使用 @vue/compiler-dom,本质原理类似但 AST 结构和生成逻辑更现代化和高效。


3. “运行”阶段:渲染函数→虚拟DOM 树

  • 执行 render 函数时,会根据当前组件的 state、props,返回一个虚拟DOM树(VNode)
  • VNode 就是个普通 JavaScript 对象,描述结构、属性、children 等。

示例:

{
  tag: 'div',
  data: { class: 'msg' },
  children: [
    { text: 'hello', ... }
  ]
}

4. VNode → 真实 DOM(Patch 阶段)

  • 首次渲染:VNode 会通过 createElement真实渲染为 DOM 元素插到页面。
  • 更新时:新旧 VNode 用 diff 算法(patch)对比出最小变更,只改动需要变的部分,提升性能。

代码伪流程:

const el = document.createElement('div')
el.className = 'msg'
el.textContent = this.msg
parent.appendChild(el)

二、流程图示

模板(template)
  ↓ (编译器)
render 函数 (js 代码)
  ↓(运行期调用)
VNode树(虚拟DOM)
  ↓(patch、diff)
真实DOM

三、Vue 模板编译原理总述

1. 核心:将模板转为 render 函数(JS代码)

  • 本质=先 template →_AST → render 函数(代码字符串),再 new Function 变为可执行函数

2. 运行时用 render 函数生成每一次的 VNode 树

  • 响应式触发重新渲染会重新执行 render 函数,得到新的 VNode

3. 新旧 VNode diff 对比,经过 patch 算法,最优地同步到真实 DOM


四、和 React 的对比一句话

  • React:JSX(编译阶段变)→ createElement → 虚拟DOM → Fiber → 真实DOM
  • Vue:模板(编译时期或运行时变)→ render 函数 → VNode(虚拟DOM)→ diff/pacth → 真实DOM

两者“虚拟DOM”思想类似,Vue 的模板编译比 React JSX 多了一步“HTML 字符串 → render 函数” AST 语法变换。


五、面试、原理中高频问法总结

  1. 模板编译阶段是什么?
    • 把 template 字符串转成 render 函数。包含 parse、optimize、codegen 三步。
  2. 虚拟DOM和真实DOM的关系?
    • VNode是内存结构,描述UI。最终由 patch 算法变成真实 DOM。
  3. 静态节点优化怎么做?
    • 编译阶段会分析哪些节点不会变,渲染/更新时跳过,提高性能。

六、扩展补充

  • Vue 3 的编译和 VNode 结构有演进,但核心“模板 → render → VNode → DOM”思路不变。
  • Vue 2 和 Vue 3 的 diff 算法、静态提升、响应式设计有变化,但流程主轴一致。

如需具体代码分析、AST结构、diff算法、Vue2/3细节区别等都可以继续追问!