回顾vue3组件在运行过程中的编译提升

一、Vue 编译流程概述

Vue 组件的编译全流程可以分为以下几个核心阶段:

  1. 模板解析:将 HTML 模板字符串解析为抽象语法树(AST)

  2. 优化阶段:标记静态节点,提高渲染效率

  3. 代码生成:将 AST 转换为渲染函数代码(render function)

  4. 运行时渲染:通过渲染函数生成虚拟 DOM(VNode)

  5. 挂载与更新:将 VNode 转换为真实 DOM 并处理更新

下面是整个编译流程的简化图示:

复制代码
┌───────────────────────────────────────────────────────────┐
│                      Vue 组件编译流程                       │
├───────────────────────────────────────────────────────────┤
│  编译时阶段(仅在开发环境或预编译时执行)                    │
│                                                           │
│  模板字符串 ──→ 解析器 ──→ AST ──→ 优化器 ──→ 代码生成器 ──→ 渲染函数
│                                                           │
├───────────────────────────────────────────────────────────┤
│  运行时阶段(每次渲染或更新时执行)                          │
│                                                           │
│  渲染函数 ──→ VNode ──→ 真实 DOM ──→ 视图更新(数据变化时)
│                                                           │
└───────────────────────────────────────────────────────────┘

二、编译时阶段详解

1. 模板解析(Template Parsing)

Vue 首先将组件的 template 选项转换为抽象语法树(AST)。这个过程使用了一个基于状态机的解析器,逐字符解析模板字符串,识别标签、属性、文本等内容。

关键步骤

  • 词法分析:将模板字符串分割为 tokens(如开始标签、结束标签、文本等)

  • 语法分析:根据 tokens 构建 AST 树结构

示例模板

预览

xml 复制代码
<div class="container">
  <h1>{{ message }}</h1>
  <button @click="increment">+1</button>
</div>

对应的简化 AST

javascript

yaml 复制代码
{
  type: 1,
  tag: 'div',
  attrsList: [{ name: 'class', value: 'container' }],
  children: [
    {
      type: 1,
      tag: 'h1',
      children: [
        {
          type: 2,
          expression: '_s(message)',
          text: '{{ message }}'
        }
      ]
    },
    {
      type: 1,
      tag: 'button',
      attrsList: [{ name: '@click', value: 'increment' }],
      children: [{ type: 3, text: '+1' }]
    }
  ]
}

2. 优化阶段(Optimization)

优化器遍历 AST,标记出所有静态节点(内容不会变化的节点)。这个步骤在 Vue 2.5+ 中引入,主要目的是在运行时提高更新效率。

优化器的作用

  • 标记静态节点和静态根节点

  • 在后续更新时跳过这些节点的比对,减少计算量

静态节点示例

预览

xml 复制代码
<!-- 静态节点 -->
<div>
  <p>这是一段静态文本</p>
</div>

3. 代码生成(Code Generation)

代码生成器将优化后的 AST 转换为渲染函数代码。主要生成两种函数:

  • render 函数:主渲染函数

  • staticRenderFns 数组:静态节点的渲染函数

示例渲染函数代码

javascript

javascript 复制代码
function render() {
  with(this) {
    return _c('div', { class: 'container' }, [
      _c('h1', [_v(_s(message))]),
      _c('button', { on: { click: increment } }, [_v('+1')])
    ])
  }
}

这里的 _c_v_s 是 Vue 内部的辅助函数:

  • _c:创建 VNode(对应 createElement)
  • _v:创建文本节点
  • _s:JSON.stringify 的简写,用于处理插值表达式

三、运行时阶段详解

1. 渲染函数执行

当组件实例创建或数据变化时,Vue 会执行渲染函数生成虚拟 DOM(VNode)。

关键步骤

  • 执行 render 函数生成 VNode 树
  • 如果有静态节点,复用 staticRenderFns 生成的结果

2. 虚拟 DOM 生成

渲染函数返回的 VNode 是一个轻量级 JavaScript 对象,描述了真实 DOM 的结构和属性。

示例 VNode 结构

css 复制代码
{
  tag: 'div',
  data: { class: 'container' },
  children: [
    {
      tag: 'h1',
      children: [{ text: 'Hello Vue' }]
    },
    {
      tag: 'button',
      on: { click: () => { /* ... */ } },
      children: [{ text: '+1' }]
    }
  ]
}

3. 挂载与更新

  • 首次挂载 :Vue 使用 patch 函数将 VNode 转换为真实 DOM,并插入到页面中。

  • 数据更新 :当响应式数据变化时,Vue 会重新执行渲染函数生成新的 VNode,然后通过 patch 算法比较新旧 VNode,只更新需要变化的部分。

虚拟 DOM 到真实 DOM 的转换

javascript

scss 复制代码
// 简化的 patch 过程
function patch(oldVnode, newVnode) {
  if (!oldVnode) {
    // 首次渲染:创建真实 DOM
    return createElm(newVnode);
  } else {
    // 更新:比较新旧 VNode,只更新变化的部分
    updateChildren(oldVnode.children, newVnode.children);
    // ...
  }
}

四、编译模式对比

Vue 提供了两种编译模式:

  1. 完整版(包含编译器)

    • 同时包含编译器和运行时
    • 可以在浏览器中直接编译模板字符串
    • 体积较大(约 22kb min+gzip)
  2. 运行时版(不含编译器)

    • 只包含运行时,不包含编译器
    • 需要预编译模板(如使用 Vue CLI)
    • 体积更小(约 18kb min+gzip)

五、编译过程的性能优化

Vue 通过多种方式优化编译和渲染性能:

  1. 静态节点标记:优化器标记静态节点,避免重复渲染
  2. 虚拟 DOM 差异比较:只更新变化的部分
  3. 预编译:通过构建工具提前编译模板,避免运行时编译开销
  4. 事件缓存:相同事件处理函数复用,减少内存占用

六、总结

Vue 组件的编译全流程是一个将模板转换为高效渲染函数的过程,分为编译时和运行时两个阶段:

  1. 编译时:模板 → AST → 优化 → 渲染函数

  2. 运行时:渲染函数 → VNode → 真实 DOM → 更新

理解这个过程有助于:

  • 编写更高效的 Vue 组件
  • 调试和优化性能问题
  • 理解 Vue 的一些高级特性(如 render 函数、静态节点优化)
相关推荐
无名之逆38 分钟前
[特殊字符]For Speed Enthusiasts: The Ultimate Evolution of Rust HTTP Engines
开发语言·前端·后端·网络协议·http·rust
巴巴_羊41 分钟前
前端八股HTTP和https大全套
前端·http·https
不写八个2 小时前
Express教程【002】:Express监听GET和POST请求
前端·javascript·express
pianmian17 小时前
3D Tiles高级样式设置与条件渲染(3)
linux·服务器·前端
资深前端之路7 小时前
vue+threeJs 绘制3D圆形
前端·javascript·vue.js
Nymph_Zhu8 小时前
vue3+element-plus el-date-picker日期、年份筛选设置本周、本月、近3年等快捷筛选
前端·vue.js·elementui
极客密码8 小时前
DeepSeek-R1-0528,官方的端午节特别献礼
前端·ai编程·deepseek
打小就很皮...8 小时前
npm、pnpm、yarn使用以及区别
前端·npm·yarn
FungLeo9 小时前
vue2 + webpack 老项目升级 node v22 + vite + vue2 实战全记录
前端·webpack·vue2·vie·webpack 升级 vite
西洼工作室9 小时前
使用原生前端技术封装一个组件
前端·js