开篇
模板编译再整个渲染过程中的位置。
1.模板→2.模板编译→3.渲染函数→4.vnode→5.用户界面
1-3属于模板编译 3-5属于虚拟DOM
Vue.js提供了模板语法,允许我们声明式地描述状态和DOM之间的绑定关系,然后通过模板来生成真实DOM并将其呈现在用户界面上。
在底层是线上,Vue.js将模板编译成虚拟DOM渲染函数。当应用内部的状态发生变化时,Vue.js可以结合响应式系统,聪明地找出最小数量的组件进行重新渲染以及最少量地进行DOM操作。
将模板编译成渲染函数
将模板编译成渲染函数可以分为两个步骤:
1.先将模板解析成AST(Abstract Syntax Tree,抽象语法树)。
2.使用AST生成渲染函数。
由于静态节点不需要总是重新渲染,所以在生成AST之后,生成渲染函数之前这个阶段,需要遍历一遍AST,给所有的静态节点做一个标记,这样在之后虚拟DOM更新节点时,发现节点存在标记,则不会重新渲染它。
所以模板编译大体分为三个阶段并抽象出三个模块各自实现具体的功能:
1.将模板解析为AST.(解析器)
2.遍历AST标记静态节点.(优化器)
3.使用AST生成渲染函数.(代码生成器)
模板编译的整个流程
模板=输入=》解析器==》优化器==》代码生成器=输出=》渲染函数
中间这三部分叫做模板编译。
解析器
解析器内部分为:过滤器解析器,文本解析器和HTML解析器。
最重要的就是HTML解析器,它的作用就是用来解析模板,当解析到HTML标签的开始位置、结束位置、文本或者注释时,会触发解析器中的钩子函数,然后将相关信息通过参数传递出来。
每当触发钩子函数,就生成一个对应的AST节点,会根据节点类型不同生成不同的AST,类似于VNode,都是使用JS对象来表示一个节点
优化器
遍历AST来检测出静态子树并打上标记
当AST上的静态字数被打上标记后,每次重新渲染就不需要为这些静态节点创建新的虚拟节点,而是直接克隆节点,优化器的作用是为了避免一些无用功来提升性能,因为静态节点除了首次渲染,其余时候不需要进行重新渲染的操作。
代码生成器
将AST转换成渲染函数的内容,这个内容叫做“代码字符串”。
例如一个简单的模板
<p title='hello' @click="c">1</p> //生成后的代码字符串是 with(this){ return _c( 'p', { attrs:{"title":"hello"}, on:{"click":"c"} }, [_v("1")] ) }
生成一个with语句的字符串然后放在一个函数里执行,模板编译的任务就完成了。
const code = `with(this){ return xxx }` const hello = new Function(code) hello()
渲染函数的作用就是创建vnode,调用了许多函数来生成,这些函数都是虚拟DOM提供的创建vnode的方法,例如_c是创建元素类型的vnode,_v是创建文本类型的vnode
总结
模板编译成渲染函数由三部分内容:先将模板解析成AST,然后遍历AST标记静态节点,最后使用AST生成代码字符串。这三部分对应三个模块:解析器,优化器,代码生成器。