惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
云风的 BLOG
云风的 BLOG
人人都是产品经理
人人都是产品经理
T
The Blog of Author Tim Ferriss
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
J
Java Code Geeks
博客园 - 聂微东
B
Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
WordPress大学
WordPress大学
腾讯CDC
L
LangChain Blog
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Azure Blog
Microsoft Azure Blog
D
DataBreaches.Net
The GitHub Blog
The GitHub Blog
美团技术团队
博客园 - Franky
Google DeepMind News
Google DeepMind News
V
V2EX
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
The Cloudflare Blog

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12)
Vue 模板编译:HTML 是怎么变成 JS 的?
微山湖上静悄悄 · 2026-06-17 · via 博客园_首页

你写的模板,浏览器不认识

用 Vue 写代码的时候,你一定写过这样的模板:

<template>
  <div id="app">
    <p>{{ message }}</p>
    <button @click="handleClick">点击</button>
  </div>
</template>

看起来很直观。但问题是——浏览器不认识这玩意儿。{{ message }} 不是 HTML 标准,@click 也不是合法属性。你写的是"Vue 方言",Vue 必须把它翻译成浏览器能跑的纯 JavaScript,翻译结果大概长这样:

function render() {
  return h('div', { attrs: { id: 'app' } }, [
    h('p', {}, [this.message]),
    h('button', { on: { click: this.handleClick } }, ['点击'])
  ])
}

<div>{{ message }}</div>h('div', {}, [this.message]) —— 这个过程就叫模板编译

h() 是 Vue 创建虚拟 DOM 节点的方法,h('div', { id: 'app' }, children) 相当于"创建一个 div 元素,id 为 app"。


一个比喻:翻译家

模板编译就像一个翻译家,把"HTML 方言"翻译成"JavaScript 母语":

     模板(HTML 方言)              渲染函数(JS 母语)
┌──────────────────────┐      ┌──────────────────────┐
│ <div class="box">     │      │ h('div',              │
│   {{ msg }}           │  ──》 │   { class: 'box' },   │
│ </div>                │      │   [this.msg])          │
└──────────────────────┘      └──────────────────────┘

和你用翻译软件把中文翻成英文一样——换了一种语言,意思不变。


三大步骤

翻译不是一步到位的,分三步走:

模板字符串
    │
    ▼
┌─────────┐
│  Parse  │  把字符串变成 AST(抽象语法树)
│  解析    │  就像把汉语句子拆成主谓宾
└────┬────┘
     │
     ▼
┌─────────┐
│ Optimize│  标记静态节点——不会变的部分标出来
│  优化    │  省得每次重新创建,白费力气
└────┬────┘
     │
     ▼
┌─────────┐
│ Generate│  把 AST 变成代码字符串
│  生成    │  最终输出 render 函数
└────┬────┘
     │
     ▼
function render() { return h(...) }

用一个生活比喻来记:

步骤 类比 输入 输出
Parse 把一段中文拆成主谓宾定状补 HTML 字符串 AST 语法树
Optimize 标出文中"固定搭配",不用每次查词典 AST 带静态标记的 AST
Generate 把中文句子翻译成英文 优化后的 AST function render() { ... }

编译发生在什么时候?

1. 构建时编译(主流)

在用 webpack + vue-loader 或 Vite 打包时,.vue 文件里的 <template>打包阶段就被编译成了 render 函数。

开发时                    打包后(发给用户)
┌────────────┐           ┌──────────────┐
│ .vue 文件    │  ──》    │ 纯 JS 代码    │
│ <template>  │  编译    │ render 函数   │
│ <script>    │          │ 不包含编译器   │
│ <style>     │          └──────────────┘
└────────────┘

好处:用户下载的代码不含编译器(编译器本身不小),体积更小,页面打开更快。

2. 运行时编译

直接在浏览器里引入 Vue,模板写在 HTML 中,Vue 初始化时现场编译:

<div id="app">
  <p>{{ message }}</p>  <!-- 浏览器里当场编译 -->
</div>

好处:不用构建工具,写好就能跑。代价:需要引入完整版 Vue(含编译器),体积大不少。绝大多数项目都用构建时编译,运行时编译只适合快速写 demo 的场景。


一句话带走:Vue 模板编译是把 HTML 模板翻译成 JS 渲染函数的过程,分 Parse → Optimize → Generate 三步,通常在打包阶段完成。

如果喜欢文章,还请点赞一下,后续会继续用最简单的方式拆解vue源码。🙇‍