/* @flow */

import { genHandlers } from './events'
import { baseWarn, pluckModuleFunction } from '../helpers'
import baseDirectives from '../directives/index'
import { camelize } from 'shared/util' // configurable state
let warn
let transforms
let dataGenFns
let platformDirectives
let staticRenderFns
let onceCount
let currentOptions export function generate (
ast: ASTElement | void,
options: CompilerOptions
): {
render: string,
staticRenderFns: Array<string>
} {
// save previous staticRenderFns so generate calls can be nested
const prevStaticRenderFns: Array<string> = staticRenderFns
const currentStaticRenderFns: Array<string> = staticRenderFns = []
const prevOnceCount = onceCount
onceCount = 0
currentOptions = options
warn = options.warn || baseWarn
transforms = pluckModuleFunction(options.modules, 'transformCode')
dataGenFns = pluckModuleFunction(options.modules, 'genData')
platformDirectives = options.directives || {}
const code = ast ? genElement(ast) : '_h("div")'
staticRenderFns = prevStaticRenderFns
onceCount = prevOnceCount
return {
render: `with(this){return ${code}}`,
staticRenderFns: currentStaticRenderFns
}
} function genElement (el: ASTElement): string {
if (el.staticRoot && !el.staticProcessed) {
return genStatic(el)
} else if (el.once && !el.onceProcessed) {
return genOnce(el)
} else if (el.for && !el.forProcessed) {
return genFor(el)
} else if (el.if && !el.ifProcessed) {
return genIf(el)
} else if (el.tag === 'template' && !el.slotTarget) {
return genChildren(el) || 'void 0'
} else if (el.tag === 'slot') {
return genSlot(el)
} else {
// component or element
let code
if (el.component) {
code = genComponent(el.component, el)
} else {
const data = el.plain ? undefined : genData(el) const children = el.inlineTemplate ? null : genChildren(el)
code = `_h('${el.tag}'${
data ? `,${data}` : '' // data
}${
children ? `,${children}` : '' // children
})`
}
// module transforms
for (let i = 0; i < transforms.length; i++) {
code = transforms[i](el, code)
}
return code
}
} // hoist static sub-trees out
function genStatic (el: ASTElement): string {
el.staticProcessed = true
staticRenderFns.push(`with(this){return ${genElement(el)}}`)
return `_m(${staticRenderFns.length - 1}${el.staticInFor ? ',true' : ''})`
} // v-once
function genOnce (el: ASTElement): string {
el.onceProcessed = true
if (el.if && !el.ifProcessed) {
return genIf(el)
} else if (el.staticInFor) {
let key = ''
let parent = el.parent
while (parent) {
if (parent.for) {
key = parent.key
break
}
parent = parent.parent
}
if (!key) {
process.env.NODE_ENV !== 'production' && warn(
`v-once can only be used inside v-for that is keyed. `
)
return genElement(el)
}
return `_o(${genElement(el)},${onceCount++}${key ? `,${key}` : ``})`
} else {
return genStatic(el)
}
} function genIf (el: any): string {
el.ifProcessed = true // avoid recursion
return genIfConditions(el.conditions)
} function genIfConditions (conditions: ASTIfConditions): string {
if (!conditions.length) {
return '_e()'
} var condition = conditions.shift()
if (condition.exp) {
return `(${condition.exp})?${genTernaryExp(condition.block)}:${genIfConditions(conditions)}`
} else {
return `${genTernaryExp(condition.block)}`
} // v-if with v-once shuold generate code like (a)?_m(0):_m(1)
function genTernaryExp (el) {
return el.once ? genOnce(el) : genElement(el)
}
} function genFor (el: any): string {
const exp = el.for
const alias = el.alias
const iterator1 = el.iterator1 ? `,${el.iterator1}` : ''
const iterator2 = el.iterator2 ? `,${el.iterator2}` : ''
el.forProcessed = true // avoid recursion
return `_l((${exp}),` +
`function(${alias}${iterator1}${iterator2}){` +
`return ${genElement(el)}` +
'})'
} function genData (el: ASTElement): string {
let data = '{' // directives first.
// directives may mutate the el's other properties before they are generated.
const dirs = genDirectives(el)
if (dirs) data += dirs + ',' // key
if (el.key) {
data += `key:${el.key},`
}
// ref
if (el.ref) {
data += `ref:${el.ref},`
}
if (el.refInFor) {
data += `refInFor:true,`
}
// record original tag name for components using "is" attribute
if (el.component) {
data += `tag:"${el.tag}",`
}
// module data generation functions
for (let i = 0; i < dataGenFns.length; i++) {
data += dataGenFns[i](el)
}
// attributes
if (el.attrs) {
data += `attrs:{${genProps(el.attrs)}},`
}
// DOM props
if (el.props) {
data += `domProps:{${genProps(el.props)}},`
}
// event handlers
if (el.events) {
data += `${genHandlers(el.events)},`
}
if (el.nativeEvents) {
data += `${genHandlers(el.nativeEvents, true)},`
}
// slot target
if (el.slotTarget) {
data += `slot:${el.slotTarget},`
}
// scoped slots
if (el.scopedSlots) {
data += `${genScopedSlots(el.scopedSlots)},`
}
// inline-template
if (el.inlineTemplate) {
const inlineTemplate = genInlineTemplate(el)
if (inlineTemplate) {
data += `${inlineTemplate},`
}
}
data = data.replace(/,$/, '') + '}'
// v-bind data wrap
if (el.wrapData) {
data = el.wrapData(data)
}
return data
} function genDirectives (el: ASTElement): string | void {
const dirs = el.directives
if (!dirs) return
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, warn)
}
if (needRuntime) {
hasRuntime = true
res += `{name:"${dir.name}",rawName:"${dir.rawName}"${
dir.value ? `,value:(${dir.value}),expression:${JSON.stringify(dir.value)}` : ''
}${
dir.arg ? `,arg:"${dir.arg}"` : ''
}${
dir.modifiers ? `,modifiers:${JSON.stringify(dir.modifiers)}` : ''
}},`
}
}
if (hasRuntime) {
return res.slice(0, -1) + ']'
}
} function genInlineTemplate (el: ASTElement): ?string {
const ast = el.children[0]
if (process.env.NODE_ENV !== 'production' && (
el.children.length > 1 || ast.type !== 1
)) {
warn('Inline-template components must have exactly one child element.')
}
if (ast.type === 1) {
const inlineRenderFns = generate(ast, currentOptions)
return `inlineTemplate:{render:function(){${
inlineRenderFns.render
}},staticRenderFns:[${
inlineRenderFns.staticRenderFns.map(code => `function(){${code}}`).join(',')
}]}`
}
} function genScopedSlots (slots) {
return `scopedSlots:{${
Object.keys(slots).map(key => genScopedSlot(key, slots[key])).join(',')
}}`
} function genScopedSlot (key: string, el: ASTElement) {
return `${key}:function(${String(el.attrsMap.scope)}){` +
`return ${el.tag === 'template'
? genChildren(el) || 'void 0'
: genElement(el)
}}`
} function genChildren (el: ASTElement): string | void {
if (el.children.length) {
return '[' + el.children.map(genNode).join(',') + ']'
}
} function genNode (node: ASTNode) {
if (node.type === 1) {
return genElement(node)
} else {
return genText(node)
}
} function genText (text: ASTText | ASTExpression): string {
return text.type === 2
? text.expression // no need for () because already wrapped in _s()
: transformSpecialNewlines(JSON.stringify(text.text))
} function genSlot (el: ASTElement): string {
const slotName = el.slotName || '"default"'
const children = genChildren(el)
return `_t(${slotName}${
children ? `,${children}` : ''
}${
el.attrs ? `${children ? '' : ',null'},{${
el.attrs.map(a => `${camelize(a.name)}:${a.value}`).join(',')
}}` : ''
})`
} // componentName is el.component, take it as argument to shun flow's pessimistic refinement
function genComponent (componentName, el): string {
const children = el.inlineTemplate ? null : genChildren(el)
return `_h(${componentName},${genData(el)}${
children ? `,${children}` : ''
})`
} function genProps (props: Array<{ name: string, value: string }>): string {
let res = ''
for (let i = 0; i < props.length; i++) {
const prop = props[i]
res += `"${prop.name}":${transformSpecialNewlines(prop.value)},`
}
return res.slice(0, -1)
} // #3895, #4268
function transformSpecialNewlines (text: string): string {
return text
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029')
}

vue.js 源代码学习笔记 ----- codegen.js的更多相关文章

  1. vue.js 源代码学习笔记 ----- html-parse.js

    /** * Not type-checking this file because it's mostly vendor code. */ /*! * HTML Parser By John Resi ...

  2. vue.js 源代码学习笔记 ----- helpers.js

    /* @flow */ import { parseFilters } from './parser/filter-parser' export function baseWarn (msg: str ...

  3. vue.js 源代码学习笔记 ----- codegenEvents.js

    /* @flow */ const fnExpRE = /^\s*([\w$_]+|\([^)]*?\))\s*=>|^function\s*\(/ const simplePathRE = / ...

  4. vue.js 源代码学习笔记 ----- fillter-parse.js

    /* @flow */ export function parseFilters (exp: string): string { let inSingle = false let inDouble = ...

  5. vue.js 源代码学习笔记 ----- text-parse.js

    /* @flow */ import { cached } from 'shared/util' import { parseFilters } from './filter-parser' //找到 ...

  6. vue.js 源代码学习笔记 ----- 工具方法 lang

    /* @flow */ // Object.freeze 使得这个对象不能增加属性, 修改属性, 这样就保证了这个对象在任何时候都是空的 export const emptyObject = Obje ...

  7. vue.js 源代码学习笔记 ----- 工具方法 env

    /* @flow */ /* globals MutationObserver */ import { noop } from 'shared/util' // can we use __proto_ ...

  8. vue.js 源代码学习笔记 ----- 工具方法 share

    /* @flow */ /** * Convert a value to a string that is actually rendered. { .. } [ .. ] 2 => '' */ ...

  9. vue.js 源代码学习笔记 ----- instance render

    /* @flow */ import { warn, nextTick, toNumber, _toString, looseEqual, emptyObject, handleError, loos ...

随机推荐

  1. WebMagic简介和使用

    概览 WebMagic是一款简单灵活的爬虫框架.基于它你可以很容易的编写一个爬虫. WebMagic项目代码分为核心和扩展两部分. 核心部分(webmagic-core)是一个精简的.模块化的爬虫实现 ...

  2. HDU3579:Hello Kiki(解一元线性同余方程组)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3579 题目解析:求一元线性同余方程组的最小解X,需要注意的是如果X等于0,需要加上方程组通解的整数区间lc ...

  3. 为什么要同时重写equals和hashcode

    原文地址https://blog.csdn.net/tiantiandjava/article/details/46988461 原文地址https://blog.csdn.net/lijiecao0 ...

  4. Python数据结构:列表、字典、元组、集合

    列表:shoplist = ['apple', 'mango', 'carrot', 'banana']字典:di = {'a':123,'b':'something'}集合:jihe = {'app ...

  5. SpringData修改和删除操作

    SpringData的查询我们已经学完了,我们现在就研究一下SpringData的修改和删除. @Modifying 注解和事务 @Query 与 @Modifying 这两个 annotation一 ...

  6. uva11795

    这题说的是一个人要消灭 所有的机器人,但是他有他可以消灭的机器人,他可以通过它消灭的机器人的武器去消灭其他的机器人, 给了一个可以消灭的关系的矩阵,计算消灭这些机器人的顺序的不同方案是多少种 , 刚开 ...

  7. Android开发--取消AsyncTask

    在Android应用开发过程中,为了防止UI线程堵塞,耗时的工作都应该另起一个后台线程来完成,其中AsyncTask就是其中的一种方式.最近在案子中需要“停止/取消”某个AsyncTask,在网上查了 ...

  8. Html常用标记总结

    超文本标记语言的结构包括“头”部分(英语:Head).和“主体”部分(英语:body),其中“头”部提供关于网页的信息,“主体”部分提供网页的具体内容. Web页面绝大多数都是由html所编写的. 一 ...

  9. EL表达式判断条件要写在${}内

    由于老没开发框架了,今天提取公共省市县三级联动组件时,使用jsp传参搞了半天才弄出来. 组件代码 $(function(){console.log("${param.init}") ...

  10. Git-时光穿梭【转】

    本文转载自:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 时光穿梭机 我们已经成 ...