[TOC]
*****
## 6 codegen.js 代码生成
>[info] import
~~~
;(导入)事件解析,引用指令,解析助手
import { genHandlers } from './events'
import { ref } from './directives/ref'
import { baseWarn } from './helpers'
~~~
>[info] module
~~~
;基础指令
const baseDirectives = {
ref,
cloak: function () {} // noop
}
;代码生成配置选项
let warn
let platformDirectives
let isPlatformReservedTag
let staticRenderFns
let currentOptions
;代码生成接口
export function generate (ast, options) {
;保存静态渲染函数
const prevStaticRenderFns = staticRenderFns
;初始化当前渲染
const currentStaticRenderFns = staticRenderFns = []
;选项控制
currentOptions = options
warn = options.warn || baseWarn
platformDirectives = options.directives || {}
isPlatformReservedTag = options.isReservedTag || (() => false)
;ast生成代码
const code = ast ? genElement(ast) : '__h__("div")'
;恢复静态渲染函数
staticRenderFns = prevStaticRenderFns
;返回当前生成渲染函数
return {
render: `with (this) { return ${code}}`,
staticRenderFns: currentStaticRenderFns
}
}
;生成函数入口
function genElement (el) {
if (el.for) {
return genFor(el)
} else if (el.if) {
return genIf(el)
} else if (el.tag === 'template' && !el.slotTarget) {
return genChildren(el)
} else if (el.tag === 'render') {
return genRender(el)
} else if (el.tag === 'slot') {
return genSlot(el)
} else if (el.tag === 'component') {
return genComponent(el)
} else {
const children = el.inlineTemplate
? 'undefined'
: genChildren(el, !isPlatformReservedTag(el.tag) /* asThunk */)
const namespace = el.ns ? `,'${el.ns}'` : ''
const code = `__h__('${el.tag}', ${genData(el)}, ${children}${namespace})`
if (el.staticRoot) {
staticRenderFns.push(`with(this){return ${code}}`)
return `_staticTrees[${staticRenderFns.length - 1}]`
} else {
return code
}
}
}
;生成if渲染函数
function genIf (el) {
const exp = el.if
el.if = false // avoid recursion
return `(${exp}) ? ${genElement(el)} : ${genElse(el)}`
}
;生成else函数
function genElse (el) {
return el.elseBlock
? genElement(el.elseBlock)
: 'null'
}
;生成for函数
function genFor (el) {
const exp = el.for
const alias = el.alias
const iterator = el.iterator
el.for = false // avoid recursion
return `(${exp})&&__renderList__((${exp}), ` +
`function(${alias},$index,${iterator || '$key'}){` +
`return ${genElement(el)}` +
'})'
}
;生成data函数
function genData (el) {
if (el.plain) {
return 'undefined'
}
let data = '{'
// directives first.
// directives may mutate the el's other properties before they are generated.
if (el.directives) {
const dirs = genDirectives(el)
if (dirs) data += dirs + ','
}
// pre
if (el.pre) {
data += 'pre:true,'
}
// key
if (el.key) {
data += `key:${el.key},`
}
// slot target
if (el.slotTarget) {
data += `slot:${el.slotTarget},`
}
// class
if (el.staticClass) {
data += `staticClass:${el.staticClass},`
}
if (el.classBinding) {
data += `class:${el.classBinding},`
}
// style
if (el.styleBinding) {
data += `style:${el.styleBinding},`
}
// transition
if (el.transition) {
data += `transition:{definition:(${el.transition}),appear:${el.transitionOnAppear}},`
}
// v-show, used to avoid transition being applied
// since v-show takes it over
if (el.attrsMap['v-show'] || el.show) {
data += 'show:true,'
}
// props
if (el.props) {
data += `props:{${genProps(el.props)}},`
}
// attributes
if (el.attrs) {
data += `attrs:{${genProps(el.attrs)}},`
}
// static attributes
if (el.staticAttrs) {
data += `staticAttrs:{${genProps(el.staticAttrs)}},`
}
// hooks
if (el.hooks) {
data += `hook:{${genHooks(el.hooks)}},`
}
// event handlers
if (el.events) {
data += `${genHandlers(el.events)},`
}
// inline-template
if (el.inlineTemplate) {
if (process.env.NODE_ENV !== 'production' && (
el.children.length > 1 || !el.children[0].tag
)) {
warn('Inline-template components must have exactly one child element.')
}
const inlineRenderFns = generate(el.children[0], currentOptions)
data += `inlineTemplate:{render:function(){${
inlineRenderFns.render
}},staticRenderFns:[${
inlineRenderFns.staticRenderFns.map(code => `function(){${code}}`).join(',')
}]}`
}
return data.replace(/,$/, '') + '}'
}
;生成指令函数
function genDirectives (el) {
const dirs = el.directives
let res = 'directives:['
let hasRuntime = false
let i, l, dir, needRuntime
for (i = 0, l = dirs.length; i < l; i++) {
dir = dirs[i]
needRuntime = true
const gen = platformDirectives[dir.name] || baseDirectives[dir.name]
if (gen) {
// compile-time directive that manipulates AST.
// returns true if it also needs a runtime counterpart.
needRuntime = !!gen(el, dir)
}
if (needRuntime) {
hasRuntime = true
res += `{name:"${dir.name}"${
dir.value ? `,value:(${dir.value})` : ''
}${
dir.arg ? `,arg:"${dir.arg}"` : ''
}${
dir.modifiers ? `,modifiers:${JSON.stringify(dir.modifiers)}` : ''
}},`
}
}
if (hasRuntime) {
return res.slice(0, -1) + ']'
}
}
;生成子节点数组函数
function genChildren (el, asThunk) {
if (!el.children.length) {
return 'undefined'
}
const code = '[' + el.children.map(genNode).join(',') + ']'
return asThunk
? `function(){return ${code}}`
: code
}
;生成子节点函数
function genNode (node) {
if (node.tag) {
return genElement(node)
} else {
return genText(node)
}
}
;生成文本函数
function genText (text) {
return text.expression
? `(${text.expression})`
: JSON.stringify(text.text)
}
;<render>生成函数
function genRender (el) {
return `${el.renderMethod}(${el.renderArgs || 'null'},${genChildren(el)})`
}
;<slot>生成函数
function genSlot (el) {
const name = el.slotName || '"default"'
return `($slots[${name}] || ${genChildren(el)})`
}
;<component>生成函数
function genComponent (el) {
return `__h__(${el.component}, ${genData(el)}, ${genChildren(el, true)})`
}
;生成props函数
function genProps (props) {
let res = ''
for (let i = 0; i < props.length; i++) {
const prop = props[i]
res += `"${prop.name}":${prop.value},`
}
return res.slice(0, -1)
}
;生成hooks函数
function genHooks (hooks) {
let res = ''
for (const key in hooks) {
res += `"${key}":function(n1,n2){${hooks[key].join(';')}},`
}
return res.slice(0, -1)
}
~~~
>[info] export
~~~
;(导出)代码生成接口
export function generate (ast, options) {}
~~~
- 概述
- 框架结构
- 编译入口(\entries)
- web-compiler.js(web编译)
- web-runtime.js(web运行时)
- web-runtime-wih-compiler.js(web编译运行)
- web-server-renderer.js(web服务器渲染)
- 核心实现 (\core)
- index.js(核心入口)
- config.js(核心配置)
- core\util(核心工具)
- core\observer(双向绑定)
- core\vdom(虚拟DOM)
- core\global-api(核心api)
- core\instance(核心实例)
- 模板编译(\compiler)
- compiler\parser(模板解析)
- events.js(事件解析)
- helper.js(解析助手)
- directives\ref.js(ref指令)
- optimizer.js(解析优化)
- codegen.js(渲染生成)
- index.js(模板编译入口)
- web渲染(\platforms\web)
- compiler(web编译目录)
- runtime(web运行时目录)
- server(web服务器目录)
- util(web工具目录)
- 服务器渲染(\server)
- render-stream.js(流式渲染)
- render.js(服务器渲染函数)
- create-renderer.js(创建渲染接口)
- 框架流程
- Vue初始化
- Vue视图数据绑定
- Vue数据变化刷新
- Vue视图操作刷新
- 框架工具
- 基础工具(\shared)
- 模板编译助手
- 核心实例工具
- Web渲染工具
- 基础原理
- dom
- string
- array
- function
- object
- es6
- 模块(Module)
- 类(Class)
- 函数(箭头)
- 字符串(扩展)
- 代理接口(Proxy)
- 数据绑定基础
- 数据绑定实现
- mvvm简单实现
- mvvm简单使用
- vdom算法
- vdom实现
- vue源码分析资料