vue编译模版原理

Vue 编译器架构的主要任务是将VUE模板转换为可执行的 JavaScript 代码。编译的核心逻辑是获取dom,遍历dom,对于{{}}格式的变量,dom属性,v-开头和@开头的属性等,转化成浏览器可以运行的代码。这个过程涉及以下步骤:

  1. 模板到AST的转换(Parsing):
    • 词法分析:Vue 编译器首先会对模板字符串进行词法分析,将其分解成一个个词法单元(Token)。这些词法单元代表了模板中的各种元素,如标签、属性、文本等。
    • 语法分析:在词法分析的基础上,编译器会进行语法分析,将这些词法单元组织成一个抽象语法树(AST)。AST 是一种用节点表示程序结构的树状数据结构,每个节点代表模板中的一个具体元素。
  2. 优化(Optimization):
    • 在生成 AST 后,Vue 编译器会对 AST 进行静态分析和优化,标记静态节点。静态节点是指在渲染过程中不会发生变化的节点。这一步有助于提高渲染性能。
  3. 渲染函数代码生成(Code Generation):
    • 优化后的 AST 会被转换为渲染函数,这个函数能够返回虚拟 DOM 树,包括创建虚拟节点(VNode),以及对数据变化的响应逻辑。
    • 响应式系统的集成
      • 数据绑定:在编译过程中,Vue 编译器会将模板中的动态数据与 Vue 实例的数据进行绑定。这样,当数据发生变化时,视图会自动更新。
      • 指令处理:Vue 模板中可以使用各种指令(如 v-if、v-for 等)来控制元素的渲染。编译器会识别这些指令,并生成相应的逻辑代码。
  4. 静态提升(Static Hoisting):
    • Vue 编译器还会进行静态提升,将静态节点提升到渲染函数外部,避免重复创建和销毁静态节点,从而提高性能。
  5. 内联模板(Inline Templates):
    • 对于内联模板,Vue 编译器会将其直接嵌入到组件中,避免额外的编译步骤。

image-20241110160704705

伪代码,模拟实现vue编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
class Compile {
constructor(el, vm) {
this.$el = el
this.$vm = vm
}
node2Fragment(el) {
const frag = document.createDocumentFragment()
// 将el中所有子元素搬家至frag中
let child;
while(child = el.firstChile) {
frag.appendChild(child)
}
return frag
}

// 编译过程
compile(el) {
const childNodes = el.childNodes
Array.from(childNodes).forEach(node => {
// 类型判断
if (this.isElement(node)) {
// 编译元素
// 查找v- @ :
const nodeAttrs = node.attributes
Array.from(nodeAttrs).forEach(attr => {
const attrName = attr.name // 属性名
const exp = attr.value
if (this.isDirective(attrName)) {
// k-text
const dir = attrName.subtring(2)
// 执行指令
this[dir] && this[dir](node, this.$vm, exp)
}
if (this.isEvent(attrName)) {

}
})
} else if (this.isInterpolation(node)) {
// 编译插值文本
this.compileText(node)
}
// 递归子节点
if (node.childNodes && node.childNodes.length > 0) {
this.complie(node)
}
})
}

compileText(node) {
this.update(node, this.$vm, RegExp.$1, 'text')
}

// 更新函数
update(node, vm, exp, dir) {
const updaterFn = this[dir +'Updater']
// 初始化
updaterFn && updaterFn(node, vm[exp])
// 依赖收集
new Watcher(vm, exp, function(value) {
updaterFn && updaterFn(node, value)
})
}

text(node, vm, exp) {
this.update(node, this.$vm, exp, 'text')
}

textUpdater(node, value) {
node.textContent = value
}

isDirective(attr) {
return attr.indexOf('v-') == 0
}
}

vue编译过程是怎么样的?

3W1H
什么是编译?
为什么要编译?

通过编译的过程,进行依赖的收集,将data中的数据模型与视图产生绑定关系,之后如果模型发生变化的时候,我们就可以通知这些依赖进行更新,从而实现模型驱动视图的变化。

Vue 编译器架构是一个高度模块化、灵活且高效的系统,通过将模板转换为高效的渲染函数,使得 Vue 应用能够以更高效的方式渲染和更新视图。


vue编译模版原理
https://thaneyang.github.io/2024/06/vue编译模版原理.html
作者
ThaneYang
发布于
2024年6月7日
许可协议