先来看生成虚拟dom的入口文件:
...
import {
parse } from './parser/index'
import {
optimize } from './optimizer'
import {
generate } from './codegen/index'
...
const ast = parse(template.trim(), options)
if (options.optimize !== false) {
optimize(ast, options)
}
const code = generate(ast, options)
...
我们看到了AST
经过三轮加工,最终脱胎换骨
成为render function code
。那么我们这一章就来讲AST
的第三次试炼。入口文件./codegen/index
export function generate (
ast: ASTElement | void,
options: CompilerOptions
): CodegenResult {
const state = new CodegenState(options)
const code = ast ? genElement(ast, state) : '_c("div")'
return {
render: `with(this){return ${
code}}`,
staticRenderFns: state.staticRenderFns
}
}
我们来看generate
函数内部构造,返回render
是一个with(this){return ${code}}
包起来的一串东西,staticRenderFns
是在编译过程中会把那些不会变的静态节点打上标记,设置为true
,然后在渲染阶段单独渲染
。
那么genElement
函数的作用是什么呢?
export function genElement (el: ASTElement, state: CodegenState): string {
if (el.staticRoot && !el.staticProcessed) {
return genStatic(el, state)
} else if (el.once && !el.onceProcessed) {
return genOnce(el, state)
} else if (el.for && !el.forProcessed) {
return genFor(el, state)
} else if (el.if && !el.ifProcessed) {
return genIf(el, state)
} else if (el.tag === 'template' && !el.slotTarget) {
return genChildren(el, state) || 'void 0'
} else if (el.tag === 'slot') {
return genSlot(el, state)
} else {
// component or element
let code
if (el.component) {
code = genComponent(el.component, el, state)
} else {
const data = el.plain ? undefined : genData(el, state)
const children = el.inlineTemplate ? null : genChildren(el, state, true)
code = `_c('${
el.tag}'${
data ? `,${
data}` : '' // data }${
children ? `,${
children}` : '' // children })