2
0
Эх сурвалжийг харах

allow omitting data in createElement

Evan You 9 жил өмнө
parent
commit
0800fbe641

+ 1 - 1
src/compiler/codegen.js

@@ -65,7 +65,7 @@ function genElement (el: ASTElement): string {
         ? genChildren(el, !el.ns && !isPlatformReservedTag(el.tag) /* asThunk */)
         : null
       code = `_h('${el.tag}'${
-        data ? `,${data}` : children ? ',void 0' : '' // data
+        data ? `,${data}` : '' // data
       }${
         children ? `,${children}` : '' // children
       })`

+ 14 - 0
src/core/vdom/create-element.js

@@ -7,7 +7,21 @@ import { normalizeChildren } from './helpers'
 import { renderState } from '../instance/render'
 import { warn, resolveAsset } from '../util/index'
 
+// wrapper function for providing a more flexible interface
+// without getting yelled at by flow
 export function createElement (
+  tag: any,
+  data: any,
+  children: any
+): VNode | Array<VNode> | void {
+  if (data && (Array.isArray(data) || typeof data !== 'object')) {
+    children = data
+    data = undefined
+  }
+  return _createElement.call(this, tag, data, children)
+}
+
+function _createElement (
   tag?: string | Class<Component> | Function | Object,
   data?: VNodeData,
   children?: VNodeChildren | void

+ 9 - 9
test/unit/modules/compiler/codegen.spec.js

@@ -57,14 +57,14 @@ describe('codegen', () => {
   it('generate v-if directive', () => {
     assertCodegen(
       '<p v-if="show">hello</p>',
-      `with(this){return (show)?_h('p',void 0,["hello"]):void 0}`
+      `with(this){return (show)?_h('p',["hello"]):void 0}`
     )
   })
 
   it('generate v-else directive', () => {
     assertCodegen(
       '<div><p v-if="show">hello</p><p v-else>world</p></div>',
-      `with(this){return _h('div',void 0,[(show)?_h('p',void 0,["hello"]):_h('p',void 0,["world"])])}`
+      `with(this){return _h('div',[(show)?_h('p',["hello"]):_h('p',["world"])])}`
     )
   })
 
@@ -78,7 +78,7 @@ describe('codegen', () => {
   it('generate ref on v-for', () => {
     assertCodegen(
       '<ul><li v-for="item in items" ref="component1"></li></ul>',
-      `with(this){return _h('ul',void 0,[(items)&&_l((items),function(item){return _h('li',{ref:"component1",refInFor:true})})])}`
+      `with(this){return _h('ul',[(items)&&_l((items),function(item){return _h('li',{ref:"component1",refInFor:true})})])}`
     )
   })
 
@@ -92,7 +92,7 @@ describe('codegen', () => {
   it('generate template tag', () => {
     assertCodegen(
       '<template><p>{{hello}}</p></template>',
-      `with(this){return [_h('p',void 0,[_s(hello)])]}`
+      `with(this){return [_h('p',[_s(hello)])]}`
     )
   })
 
@@ -114,7 +114,7 @@ describe('codegen', () => {
     assertCodegen(
       '<slot><div>hi</div></slot>',
       `with(this){return ($slots["default"]||[_m(0)])}`,
-      [`with(this){return _h('div',void 0,["hi"])}`]
+      [`with(this){return _h('div',["hi"])}`]
     )
   })
 
@@ -275,7 +275,7 @@ describe('codegen', () => {
     assertCodegen(
       '<my-component name="mycomponent1" :msg="msg" @notify="onNotify"><div>hi</div></my-component>',
       `with(this){return _h('my-component',{attrs:{"msg":msg},staticAttrs:{"name":"mycomponent1"},on:{"notify":onNotify}},function(){return [_m(0)]})}`,
-      [`with(this){return _h('div',void 0,["hi"])}`]
+      [`with(this){return _h('div',["hi"])}`]
     )
   })
 
@@ -294,7 +294,7 @@ describe('codegen', () => {
     // have "inline-template'"
     assertCodegen(
       '<my-component inline-template><p>hello world</p></my-component>',
-      `with(this){return _h('my-component',{inlineTemplate:{render:function(){with(this){return _m(0)}},staticRenderFns:[function(){with(this){return _h('p',void 0,["hello world"])}}]}})}`
+      `with(this){return _h('my-component',{inlineTemplate:{render:function(){with(this){return _m(0)}},staticRenderFns:[function(){with(this){return _h('p',["hello world"])}}]}})}`
     )
     // "have inline-template attrs, but not having extactly one child element
     assertCodegen(
@@ -313,7 +313,7 @@ describe('codegen', () => {
   it('not specified directives option', () => {
     assertCodegen(
       '<p v-if="show">hello world</p>',
-      `with(this){return (show)?_h('p',void 0,["hello world"]):void 0}`,
+      `with(this){return (show)?_h('p',["hello world"]):void 0}`,
       { isReservedTag }
     )
   })
@@ -324,7 +324,7 @@ describe('codegen', () => {
     assertCodegen(
       '<div><p>hello world</p></div>',
       `with(this){return _m(0)}`,
-      [`with(this){return _h('div',void 0,function(){return [_h('p',void 0,function(){return ["hello world"]})]})}`],
+      [`with(this){return _h('div',function(){return [_h('p',function(){return ["hello world"]})]})}`],
       { directives }
     )
   })

+ 50 - 17
test/unit/modules/vdom/create-element.spec.js

@@ -13,9 +13,9 @@ describe('create-element', () => {
     const vm = new Vue({
       data: { msg: 'hello world' }
     })
-    const _h = bind(createElement, vm)
+    const h = bind(createElement, vm)
     renderState.activeInstance = vm
-    const vnode = _h('p', {})
+    const vnode = h('p', {})
     expect(vnode.tag).toBe('p')
     expect(vnode.data).toEqual({})
     expect(vnode.children).toBeUndefined()
@@ -34,9 +34,9 @@ describe('create-element', () => {
         }
       }
     })
-    const _h = bind(createElement, vm)
+    const h = bind(createElement, vm)
     renderState.activeInstance = vm
-    const vnode = _h('my-component', { props: { msg: vm.message }})
+    const vnode = h('my-component', { props: { msg: vm.message }})
     expect(vnode.tag).toMatch(/vue-component-[0-9]+/)
     expect(vnode.componentOptions.propsData).toEqual({ msg: vm.message })
     expect(vnode.children).toBeUndefined()
@@ -50,10 +50,10 @@ describe('create-element', () => {
     const vm = new Vue({
       data: { msg: 'hello world' }
     })
-    const _h = bind(createElement, vm)
+    const h = bind(createElement, vm)
     const tag = 'custom-tag'
     renderState.activeInstance = vm
-    const vnode = _h(tag, {})
+    const vnode = h(tag, {})
     expect(vnode.tag).toBe('custom-tag')
     expect(vnode.data).toEqual({})
     expect(vnode.children).toBeUndefined()
@@ -69,9 +69,9 @@ describe('create-element', () => {
     const vm = new Vue({
       data: { msg: 'hello world' }
     })
-    const _h = bind(createElement, vm)
+    const h = bind(createElement, vm)
     renderState.activeInstance = vm
-    const vnode = _h(null, {})
+    const vnode = h(null, {})
     expect(vnode).toEqual(emptyVNode())
   })
 
@@ -79,9 +79,9 @@ describe('create-element', () => {
     const vm = new Vue({
       data: { msg: 'hello world' }
     })
-    const _h = bind(createElement, vm)
+    const h = bind(createElement, vm)
     renderState.activeInstance = vm
-    const vnode = _h(Vue.extend({ // Component class
+    const vnode = h(Vue.extend({ // Component class
       props: ['msg']
     }), { props: { msg: vm.message }})
     expect(vnode.tag).toMatch(/vue-component-[0-9]+/)
@@ -97,22 +97,32 @@ describe('create-element', () => {
     const vm = new Vue({
       data: { msg: 'hello world' }
     })
-    const _h = bind(createElement, vm)
-    _h('p', {})
+    const h = bind(createElement, vm)
+    h('p', {})
     expect('createElement cannot be called outside of component').toHaveBeenWarned()
   })
 
   it('render vnode with createElement with children', () => {
     const vm = new Vue({})
-    const _h = bind(createElement, vm)
+    const h = bind(createElement, vm)
     renderState.activeInstance = vm
-    const vnode = _h('p', void 0, [_h('br'), 'hello world', _h('br')])
+    const vnode = h('p', void 0, [h('br'), 'hello world', h('br')])
     expect(vnode.children[0].tag).toBe('br')
     expect(vnode.children[1].text).toBe('hello world')
     expect(vnode.children[2].tag).toBe('br')
   })
 
-  it('warn message when use createElementWithChildren for component', () => {
+  it('render vnode with children, omitting data', () => {
+    const vm = new Vue({})
+    const h = bind(createElement, vm)
+    renderState.activeInstance = vm
+    const vnode = h('p', [h('br'), 'hello world', h('br')])
+    expect(vnode.children[0].tag).toBe('br')
+    expect(vnode.children[1].text).toBe('hello world')
+    expect(vnode.children[2].tag).toBe('br')
+  })
+
+  it('warn message when using non-thunk children for component', () => {
     const vm = new Vue({
       data: { message: 'hello world' },
       components: {
@@ -121,12 +131,35 @@ describe('create-element', () => {
         }
       }
     })
-    const _h = bind(createElement, vm)
+    const h = bind(createElement, vm)
     renderState.activeInstance = vm
-    const vnode = _h('my-component', { props: { msg: vm.message }}, [_h('br'), 'hello world', _h('br')])
+    const vnode = h('my-component', { props: { msg: vm.message }}, [h('br'), 'hello world', h('br')])
     expect(vnode.componentOptions.children[0].tag).toBe('br')
     expect(vnode.componentOptions.children[1]).toBe('hello world')
     expect(vnode.componentOptions.children[2].tag).toBe('br')
     expect('A component\'s children should be a function').toHaveBeenWarned()
   })
+
+  it('render svg elements with correct namespace', () => {
+    const vm = new Vue({})
+    const h = bind(createElement, vm)
+    renderState.activeInstance = vm
+    const vnode = h('svg', [h('a')])
+    expect(vnode.ns).toBe('svg')
+    // should apply ns to children
+    expect(vnode.children[0].ns).toBe('svg')
+  })
+
+  it('render MathML elements with correct namespace', () => {
+    const vm = new Vue({})
+    const h = bind(createElement, vm)
+    renderState.activeInstance = vm
+    const vnode = h('math', [h('matrix')])
+    expect(vnode.ns).toBe('math')
+    // should apply ns to children
+    expect(vnode.children[0].ns).toBe('math')
+    // although not explicitly listed, elements nested under <math>
+    // should not be treated as component
+    expect(vnode.children[0].componentOptions).toBeUndefined()
+  })
 })