From b66be950f54cf3294f23db34e9e0a3ba09ce9ada Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 29 Apr 2016 14:29:36 -0400 Subject: [PATCH] support inline-template --- src/compiler/codegen.js | 39 ++++++++++++++++++++++++------- src/compiler/helpers.js | 4 ++++ src/compiler/parser/index.js | 11 +++++---- src/core/vdom/create-component.js | 11 +++++++-- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/compiler/codegen.js b/src/compiler/codegen.js index 99bbf98f..3254e4cb 100644 --- a/src/compiler/codegen.js +++ b/src/compiler/codegen.js @@ -1,26 +1,32 @@ import { genHandlers } from './events' import { ref } from './directives/ref' +import { baseWarn } from './helpers' const baseDirectives = { ref, cloak: function () {} // noop } -// platform-injected utils +// configurable state +let warn let platformDirectives let isPlatformReservedTag - -// reset on each call let staticRenderFns +let currentOptions export function generate (ast, options) { - staticRenderFns = [] + // save previous staticRenderFns so generate calls can be nested + const prevStaticRenderFns = staticRenderFns + const currentStaticRenderFns = staticRenderFns = [] + currentOptions = options + warn = options.warn || baseWarn platformDirectives = options.directives || {} isPlatformReservedTag = options.isReservedTag || (() => false) const code = ast ? genElement(ast) : '__h__("div")' + staticRenderFns = prevStaticRenderFns return { render: `with (this) { return ${code}}`, - staticRenderFns + staticRenderFns: currentStaticRenderFns } } @@ -40,8 +46,11 @@ function genElement (el) { } else { // if the element is potentially a component, // wrap its children as a thunk. - const children = genChildren(el, !isPlatformReservedTag(el.tag) /* asThunk */) - const code = `__h__('${el.tag}', ${genData(el)}, ${children}, '${el.ns || ''}')` + 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) { // hoist static sub-trees out staticRenderFns.push(`with(this){return ${code}}`) @@ -138,7 +147,21 @@ function genData (el) { } // event handlers if (el.events) { - data += genHandlers(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(/,$/, '') + '}' } diff --git a/src/compiler/helpers.js b/src/compiler/helpers.js index e5639490..bc7657fb 100644 --- a/src/compiler/helpers.js +++ b/src/compiler/helpers.js @@ -1,5 +1,9 @@ import { isArray } from 'shared/util' +export function baseWarn (msg) { + console.error(`[Vue parser]: ${msg}`) +} + export function addProp (el, name, value) { (el.props || (el.props = [])).push({ name, value }) } diff --git a/src/compiler/parser/index.js b/src/compiler/parser/index.js index 6605ca01..97804646 100644 --- a/src/compiler/parser/index.js +++ b/src/compiler/parser/index.js @@ -9,7 +9,8 @@ import { addStaticAttr, addHandler, addDirective, - getBindingAttr + getBindingAttr, + baseWarn } from '../helpers' const dirRE = /^v-|^@|^:/ @@ -23,11 +24,8 @@ const camelRE = /[a-z\d][A-Z]/ const decodeHTMLCached = cached(decodeHTML) -// make warning customizable depending on environment. +// configurable state let warn -const baseWarn = msg => console.error(`[Vue parser]: ${msg}`) - -// other configurable options let platformGetTagNamespace let platformMustUseProp let delimiters @@ -295,6 +293,9 @@ function processComponent (el) { if (el.tag === 'component') { el.component = getBindingAttr(el, 'is') } + if (getAndRemoveAttr(el, 'inline-template') != null) { + el.inlineTemplate = true + } } function processClassBinding (el) { diff --git a/src/core/vdom/create-component.js b/src/core/vdom/create-component.js index 3dac39c9..c415cd65 100644 --- a/src/core/vdom/create-component.js +++ b/src/core/vdom/create-component.js @@ -67,13 +67,20 @@ export function createComponent (Ctor, data, parent, children, context) { function init (vnode) { const { Ctor, propsData, listeners, parent, children } = vnode.componentOptions - const child = new Ctor({ + const options = { parent, propsData, _parentVnode: vnode, _parentListeners: listeners, _renderChildren: children - }) + } + // check inline-template render functions + const inlineTemplate = vnode.data.inlineTemplate + if (inlineTemplate) { + options.render = inlineTemplate.render + options.staticRenderFns = inlineTemplate.staticRenderFns + } + const child = new Ctor(options) // if this is a server-rendered mount, // the vnode would already have an element. // otherwise the child sets the parent vnode's elm when mounted