解析器
将模板字符串转成element ast
通过正则去匹配生成一个 AST 树
例如:
<div>
<p>{{ name }}</p>
</div>
生成对应的ast
{
tag: "div"
type: 1,
staticRoot: false,
static: false,
plain: true,
parent: undefined,
attrsList: [],
attrsMap: {},
children: [
{
tag: "p"
type: 1,
staticRoot: false,
static: false,
plain: true,
parent: {tag: "div", ...},
attrsList: [],
attrsMap: {},
children: [{
type: 2,
text: "{{name}}",
static: false,
expression: "_s(name)"
}]
}
]
}
通过正则去匹配起始标签生成对应的tag等信息
通过一个栈记录一个层级,用来记录DOM的深度
当解析到一个 开始标签 或者 文本,无论是什么, stack 中的最后一项,永远是当前正在被解析的节点的 parentNode 父节点
总结: 模板解析器一部分是 截取 字符串,一部分是对截取之后的字符串做 解析,每截取一段标签的开头就 push 到 stack中,解析到标签的结束就 pop 出来,当所有的字符串都截没了也就解析完了。
优化器
标记静态节点打上标记,静态节点指dom不需要变的点
打上静态节点有两个好处
1.重新渲染的时候不需要重新生成
2.在虚拟dom打补丁的时候可以直接跳过
方法:
1.递归遍历树给每个节点打上static标记,并确认是否是静态节点
2.找出是否为静态根节点
静态节点: 1. type 为2
2. node.pre 为 true && node.hasBindings (/v-|@|^:/)不能为 true
&& 元素节点不能有 if 和 for属性。
&& 元素节点不能是 slot 和 component
&& 元素节点不能是组件
&& 元素节点的父级节点不能是带 v-for 的 template
代码生成器
element ASTs 生成 render 函数代码字符串
with(this){
return _c(
'div',
[
_c(
'p',
[
_v(_s(name))
]
)
]
)
}
_c 对应的是 createElement,它的作用是创建一个元素。
第一个参数是一个HTML标签名
第二个参数是元素上使用的属性所对应的数据对象,可选项
第三个参数是 children
_v 的意思是创建一个文本节点。
_s 是返回参数中的字符串。
代码生成器的总体逻辑其实就是使用 element ASTs 去递归,然后拼出这样的 _c(‘div’,[_c(‘p’,[_v(_s(name))])]) 字符串