Răsfoiți Sursa

functional components

Evan You 10 ani în urmă
părinte
comite
d398023ad1

+ 4 - 1
src/core/vdom/create-component.js

@@ -51,7 +51,10 @@ export function createComponent (
   data = data || {}
 
   // merge component management hooks onto the placeholder node
-  mergeHooks(data)
+  // only need to do this if this is not a functional component
+  if (!Ctor.options.functional) {
+    mergeHooks(data)
+  }
 
   // extract props
   const propsData = extractProps(data, Ctor)

+ 17 - 3
src/core/vdom/create-element.js

@@ -10,9 +10,10 @@ import { warn, resolveAsset } from '../util/index'
 export function renderElementWithChildren (
   vnode: VNode | void,
   children: VNodeChildren | void
-): VNode | void {
+): VNode | Array<VNode> | void {
   if (vnode) {
-    if (vnode.componentOptions) {
+    const componentOptions = vnode.componentOptions
+    if (componentOptions) {
       if (process.env.NODE_ENV !== 'production' &&
         children && typeof children !== 'function') {
         warn(
@@ -21,8 +22,21 @@ export function renderElementWithChildren (
           'dependencies and optimizes re-rendering.'
         )
       }
-      vnode.componentOptions.children = children
+      const CtorOptions = componentOptions.Ctor.options
+      // functional component
+      if (CtorOptions.functional) {
+        return CtorOptions.render.call(
+          null,
+          componentOptions.parent.$createElement, // h
+          componentOptions.propsData || {},       // props
+          normalizeChildren(children)             // children
+        )
+      } else {
+        // normal component
+        componentOptions.children = children
+      }
     } else {
+      // normal element
       vnode.setChildren(normalizeChildren(children))
     }
   }

+ 24 - 0
test/unit/features/options/functional.spec.js

@@ -0,0 +1,24 @@
+import Vue from 'vue'
+
+describe('Options functional', () => {
+  it('should work', done => {
+    const vm = new Vue({
+      data: { test: 'foo' },
+      template: '<div><wrap :msg="test">bar</wrap></div>',
+      components: {
+        wrap: {
+          functional: true,
+          props: ['msg'],
+          render (h, props, children) {
+            return h('div', null, [props.msg, ' '].concat(children))
+          }
+        }
+      }
+    }).$mount()
+    expect(vm.$el.innerHTML).toBe('<div>foo bar</div>')
+    vm.test = 'qux'
+    waitForUpdate(() => {
+      expect(vm.$el.innerHTML).toBe('<div>qux bar</div>')
+    }).then(done)
+  })
+})