(1)在Vue.js中创建HTML并不是只有模板这一种途径。既可以手动写渲染函数来创建HTML,也可以在Vue.js中使用JSX来创建HTML。
(2)渲染函数是创建HTML最原始的方法。
(3)模板最终会通过编译转换成渲染函数,渲染函数执行后,会得到一份vnode用于虚拟DOM渲染。所以模板编译其实是配合虚拟DOM进行渲染。
(4)模板编译所介绍的内容是如何让虚拟DOM拿到vnode。(模板--》模板编译--》渲染函数(模板编译)--》vnode--》用户界面(虚拟DOM))
(5)Vue.js提供了模板语法,允许声明式地描述状态和DOM之间地绑定关系,然后通过模板来生成真实DOM并将其呈现在用户界面上。
(6)在底层实现上,Vue.js会将模板编译成虚拟DOM渲染函数。当应用内部地状态发生变化时,Vue.js可以结合响应式系统,聪明地找出最小数量地组件进行重新渲染以及最少量地进行DOM操作。
(1)平时使用模板时,可以在模板中使用一些变量来填充模板,还可以在模板中使用Javascript表达式,又或者是使用一些指令等。这些功能在HTML语法中是不存在的,这多亏了模板编译赋予了模板强大的功能。
(2)模板编译的主要目标就是生成渲染函数。而渲染函数的作用是每次执行它,它就会使用当前最新的状态生成一份新的vnode,然后使用这个vnode进行渲染。
(1)模板编译分三部分内容
1、将模板解析为AST。(Abstract Syntax Tree,抽象语法树)。
2、遍历AST标记静态节点。
3、使用AST生成渲染函数。
(2)由于静态节点不需要总是重新渲染,所以在生成AST之后、生成渲染函数之前这个节点,需要做一个操作,那就是遍历一遍AST,给所有静态节点做一个标记,这样在虚拟DOM中更新节点时,如果发现节点有这个标记,就不会重新渲染它。
(3)这三部分内容在模板编译中分别抽象出三个模块来实现各自的功能,分别是
1、解析器。
2、优化器。
3、代码生成器。
(1)作用:将模板解析成AST。
(2)在解析器内部,分成了很多小解析器,其中包括过滤器解析器、文本解析器和HTML解析器。然后通过一条主线将这些解析器组装在一起。
(3)在使用模板时,我们可以在其中使用过滤器,而过滤器解析器的作用就是用来解析过滤器的。
(4)文本解析器就是用来解析文本的。其主要作用是用来解析带变量的文本。不带变量的文本是一段纯文本,不需要使用文本解析器来解析。
Hello {{name}}
(5)HTML解析器,它是解析器中最核心的模块,它的作用就是解析模板,每当解析到HTML标签的开始位置、结束位置、文本或则注释时,都会触发钩子函数,然后将相关信息通过参数传递进来。
(6)主线上做的事就是监听HTML解析器。每当触发钩子函数时,就生成一个对应的AST节点。生成AST节点前,会根据类型使用不同的方式生成不同的AST。例如,如果是文本节点,就生成文本类型的AST。
(7)这个AST其实和vnode有点类似,都是使用Javascript中的对象来表示节点。
(8)当HTML解析器把所有模板都解析完毕后,AST也就生成好了。
(1)目标:遍历AST,检测出所有静态子树(永远都不会发生变化的DOM节点)并给其打标记。
(2)当AST中的静态子树被打上标记后,每次重新渲染时,就不需要为打上标记的静态节点创建新的虚拟节点,而是直接克隆已存在的虚拟节点。
(3)在虚拟DOM的更新操作中,如果发现两个是同一个节点,正常情况下会对这两个节点进行更新,但是如果这两个节点是静态节点,则可以直接跳过更新节点的流程。
(4)优化器的主要作用是避免一些无用功来提升性能。因为静态节点出了首次渲染,后续不需要任何重新渲染操作。
(1)其是模板编译的最后一步,作用是将AST转换成渲染函数中的内容,这个内容可以称为“代码字符串”。
1
生成后的代码字符串:
with(this){
return _c(
'p',
{
attrs:{"title""Berwin"},
on:{"click":c}
},
[_v("1")]
)
}
(2)这样一个代码字符串最终导出到外界使用时,会将代码字符串放到函数里,这个函数叫作渲染函数。
(3)当渲染函数被导出到外界后,模板编译的任务就完成了。
const code = 'with(this){return 'Hello Berwin'}';
const hello = new Function(code);
hello();
//Hello Berwin
(4)渲染函数的作用是创建vnode。渲染函数之所以可以生成vnode,是因为代码字符串中会有很多函数调用(例如,上面生成的代码字符串中有两个函数调用_c 和 _v),这些函数是虚拟DOM提供的创建vnode的方法。
(5)vnode有很多种类型,不同类型对应不同的创建方法,所以代码字符串中的_c 和 _v其实都是创建vnode的方法,只是创建vnode的类型不同,例如_c 可以创建元素类型的vnode,而 _v可以创建文本类型的vnode。