模板编译总流程
从前面的学习中,我们知道,Vue中的虚拟DOM是由VNode实例化而来。那么VNode的数据源又是从哪里来的?答案是通过模板编译而来。简单来说,就是把用户写的模板进行编译,就会产生VNode。
什么是模板编译
Vue中,把写在标签中的类似于原生HTML的内容称之为模板。
为什么说是类似于原生HTML内容,因为在Vue中,标签中除了原生HTML标签,还会有变量插值,以及v-on、v-if等指令。
这些东西都是在原生HTML语法中不存在的。但是在Vue中,这些东西都被正确识别并显示了,这是为什么呢?
因为模板编译。
Vue会将用户在<template></template>标签中写的内容进行编译,然后把原生HTML的内容找出来,再把非原生HTML也找出来,最后经过一系列的逻辑处理生成渲染函数(render函数),最终经由render函数将模板内容生成对应的VNode。
这一过程称之为模板编译。
模板编译流程
模板编译的主要目标就是生成渲染函数,为了达到此目的,需要三步走。
1.第一步:将模板解析为AST(抽象语法树)
2.第二步:遍历AST标记静态节点
3.第三步:使用AST生成渲染函数
这三步在模板编译中分别抽象出三个模块来实现各自的功能,分别是:
1.解析器
2.优化器
3.代码生成器。
用图表示如下:
解析器
解析器的作用就是将模板编译成AST。
在解析器内部,分成了很多小解析器,其中包括过滤器解析器、文本解析器和HTML解析器,然后通过一条主线将这些解析器组装在一起。
过滤器解析器就是用来解析过滤器的。
文本解析器就是用来解析带变量的文本的。例如: hello {{name}}
HTML解析器是用来解析模板的,它是解析器中最核心的模块,每当解析到HTML标签的开始位置、结束位置、文本或者注释时,都会触发钩子函数,然后将相关信息通过参数传递出来。
主线上做的事就是监听HTML解析器,每当触发钩子函数时,就生成一个对应的AST节点。这个AST其实和VNode有点类似,都是使用JS中的对象来表述节点。
优化器
由于静态节点不需要总是重新渲染,所以在生成AST之后,生成渲染函数之前这个阶段,需要遍历一遍AST,给所有的静态节点做一个标记,这样在虚拟DOM中更新节点时,如果发现节点有这个标记,就不会重新渲染它。
优化器的功用就是遍历AST,检测出所有的静态节点并给其打标记。
当AST中的静态节点被打上标记后,每次重新渲染时,就不需要为打上标记的静态节点创建新的虚拟节点,而是直接克隆已存在的虚拟节点。在虚拟DOM更新操作中,如果两个节点是同一个节点且是静态节点,则可以直接跳过更新节点的流程,从而避免做一些无用功,进而提升性能。
代码生成器
代码生成器是模板编译的最后一步,它的作用是将AST转换成渲染函数中的内容(代码字符串)。
例如,一个简单的模板
<div id="NLRX"><p>Hello {{name}}</p></div>
生成的代码字符串是
_c('div',{attrs:{"id":"NLRX"}},[_c('p'),[_v("Hello "+_s(name))]])
当将代码字符串放到渲染函数中并导出到外界后,模板的编译的任务就完成了。