编译流程:javascript
A[]
,B[]
。A
数组中,同时去除模板字符串中的匹配部分。children[]
)等信息,设置节点的父节点指向当前父节点(currentParent),将语法树节点添加到添加到数组B
中,同时设置节点为当前父节点。B
中的节点(数组中的最后一个节点),并从数组B
中移除,同时设置数组的最后一个节点为当前父节点,将找到的节点添加到当前父节点的子节点数组children[]
中。A
中和结束标签名称相同的起始标签,并从数组A
中移除。经过数组A
能够匹配开始标签对应的结束标签。经过数组B
构建层级结构,造成语法树。构建过程是一个深度遍历。对数组
A
、B
的操做和栈一致。java根节点指向第一个添加到数组
B
的节点,最后返回根节点。node
遍历语法树,标记语法树中的静态节点。根据以前的标记结果,再遍历标记静态根节点。在渲染时,对有标记静态根节点的子树进行缓存,下次渲染时直接从缓存中读取。express
知足如下一个条件且子节点也都是静态节点:数组
function isStatic (node) { if (node.type === 2) { // expression return false } if (node.type === 3) { // text return true } return !!(node.pre || ( !node.hasBindings && // no dynamic bindings !node.if && !node.for && // not v-if or v-for or v-else !isBuiltInTag(node.tag) && // not a built-in 不是内建组件slot,component isPlatformReservedTag(node.tag) && // not a component 是原生标签 !isDirectChildOfTemplateFor(node) &&// 不是有for指令的template标签的子标签 Object.keys(node).every(isStaticKey)// 节点上的每一个属性都是静态属性 )) }
节点自己是静态节点,而且包含子节点,若是只有一个子节点,该子节点不能是纯文本节点(若是不知足这些条件作优化,成本将会超过它带来的价值)。缓存
// For a node to qualify as a static root, it should have children that // are not just static text. Otherwise the cost of hoisting out will // outweigh the benefits and it's better off to just always render it fresh. if (node.static && node.children.length && !( node.children.length === 1 &&// 1.静态节点(子节点都是静态节点),2. 包含子节点,3. 但又不是只有一个文本子节点 node.children[0].type === 3 )) { node.staticRoot = true; return } else { node.staticRoot = false; }
遍历语法树,根据每一个节点生成表达式字符串,而后拼接或者嵌套这些字符串,最后造成一个和语法树对应的完整的表达式字符串,渲染时经过with执行字符串中的表达式,生成虚拟节点树。优化
function generate ( ast, options ) { var state = new CodegenState(options); var code = ast ? genElement(ast, state) : '_c("div")';// 完整的表达式字符串 return { render: ("with(this){return " + code + "}"), staticRenderFns: state.staticRenderFns// 保存了静态根节点子树生成的表达式字符串 } }
在遍历过程当中,将有标记静态根节点的子树生成的表达式字符串保存到单独的数组中,完整的表达式字符串保存了静态子树表达式字符串在数组中的索引。ui
function genStatic (el, state) { el.staticProcessed = true; var originalPreState = state.pre; if (el.pre) { state.pre = el.pre; } state.staticRenderFns.push(("with(this){return " + (genElement(el, state)) + "}")); state.pre = originalPreState; return ("_m(" + (state.staticRenderFns.length - 1) + (el.staticInFor ? ',true' : '') + ")")// 保存静态子树表达式字符串在数组中的索引 }