在编写 Vue 代码时,你一定见过类似的模板结构:

{{ message }}
看起来非常直观,对不对?然而,浏览器根本不识别这种语法。{{ message }} 并非 HTML 标准,@click 也不是合法属性。你书写的是“Vue 专属语法”,Vue 必须将其转换为浏览器能直接运行的纯 JavaScript。转换后的结果大致如下:
function render() {
return h('div', { attrs: { id: 'app' } }, [
h('p', {}, [this.message]),
h('button', { on: { click: this.handleClick } }, ['点击'])
])
}
从 {{ message }} 变成 h('div', {}, [this.message]) —— 这一转化过程就叫做模板编译。
一个比喻:翻译家
模板编译的工作方式就像一位翻译家,把“HTML 方言”准确翻译成“JavaScript 母语”:
模板(HTML 方言) 渲染函数(JS 母语)
┌──────────────────────┐ ┌──────────────────────┐
│ │ │ h('div', │
│ {{ msg }} │ ──》 │ { class: 'box' }, │
│
│ │ [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 文件中的 会在构建阶段被提前编译成 render 函数。
开发时 打包后(发给用户)
┌────────────┐ ┌──────────────┐
│ .vue 文件 │ ──》 │ 纯 JS 代码 │
│ │ 编译 │ render 函数 │
│
