From 6dd73e9ee44c09f04d3f616fcce18750a55e2e4f Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 12 Mar 2018 15:39:39 -0400 Subject: [PATCH] fix: named slots for nested functional components Named slots should be respecred when passing raw children down multiple layers of functional components. fix #7710 --- src/core/vdom/create-functional-component.js | 22 +++++++++---- .../features/component/component-slot.spec.js | 31 +++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/core/vdom/create-functional-component.js b/src/core/vdom/create-functional-component.js index c4e4cf9e80e..fb21cdab218 100644 --- a/src/core/vdom/create-functional-component.js +++ b/src/core/vdom/create-functional-component.js @@ -10,6 +10,7 @@ import { installRenderHelpers } from '../instance/render-helpers/index' import { isDef, isTrue, + hasOwn, camelize, emptyObject, validateProp @@ -23,6 +24,21 @@ export function FunctionalRenderContext ( Ctor: Class ) { const options = Ctor.options + // ensure the createElement function in functional components + // gets a unique context - this is necessary for correct named slot check + let contextVm + if (hasOwn(parent, '_uid')) { + contextVm = Object.create(parent) + // $flow-disable-line + contextVm._original = parent + } else { + contextVm = parent + // $flow-disable-line + parent = parent._original + } + const isCompiled = isTrue(options._compiled) + const needNormalization = !isCompiled + this.data = data this.props = props this.children = children @@ -31,12 +47,6 @@ export function FunctionalRenderContext ( this.injections = resolveInject(options.inject, parent) this.slots = () => resolveSlots(children, parent) - // ensure the createElement function in functional components - // gets a unique context - this is necessary for correct named slot check - const contextVm = Object.create(parent) - const isCompiled = isTrue(options._compiled) - const needNormalization = !isCompiled - // support for compiled functional template if (isCompiled) { // exposing $options for renderStatic() diff --git a/test/unit/features/component/component-slot.spec.js b/test/unit/features/component/component-slot.spec.js index 28d6555ee65..286dcb9cce9 100644 --- a/test/unit/features/component/component-slot.spec.js +++ b/test/unit/features/component/component-slot.spec.js @@ -824,4 +824,35 @@ describe('Component slot', () => { expect(vm.$el.textContent).toBe('hello') }).then(done) }) + + it('should allow passing named slots as raw children down multiple layers of functional component', () => { + const CompB = { + functional: true, + render (h, { slots }) { + return slots().foo + } + } + + const CompA = { + functional: true, + render (h, { children }) { + return h(CompB, children) + } + } + + const vm = new Vue({ + components: { + CompA + }, + template: ` +
+ + foo + +
+ ` + }).$mount() + + expect(vm.$el.textContent).toBe('foo') + }) })