Skip to content

Commit 6dd73e9

Browse files
committed
fix: named slots for nested functional components
Named slots should be respecred when passing raw children down multiple layers of functional components. fix #7710
1 parent 215f877 commit 6dd73e9

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

src/core/vdom/create-functional-component.js

+16-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { installRenderHelpers } from '../instance/render-helpers/index'
1010
import {
1111
isDef,
1212
isTrue,
13+
hasOwn,
1314
camelize,
1415
emptyObject,
1516
validateProp
@@ -23,6 +24,21 @@ export function FunctionalRenderContext (
2324
Ctor: Class<Component>
2425
) {
2526
const options = Ctor.options
27+
// ensure the createElement function in functional components
28+
// gets a unique context - this is necessary for correct named slot check
29+
let contextVm
30+
if (hasOwn(parent, '_uid')) {
31+
contextVm = Object.create(parent)
32+
// $flow-disable-line
33+
contextVm._original = parent
34+
} else {
35+
contextVm = parent
36+
// $flow-disable-line
37+
parent = parent._original
38+
}
39+
const isCompiled = isTrue(options._compiled)
40+
const needNormalization = !isCompiled
41+
2642
this.data = data
2743
this.props = props
2844
this.children = children
@@ -31,12 +47,6 @@ export function FunctionalRenderContext (
3147
this.injections = resolveInject(options.inject, parent)
3248
this.slots = () => resolveSlots(children, parent)
3349

34-
// ensure the createElement function in functional components
35-
// gets a unique context - this is necessary for correct named slot check
36-
const contextVm = Object.create(parent)
37-
const isCompiled = isTrue(options._compiled)
38-
const needNormalization = !isCompiled
39-
4050
// support for compiled functional template
4151
if (isCompiled) {
4252
// exposing $options for renderStatic()

test/unit/features/component/component-slot.spec.js

+31
Original file line numberDiff line numberDiff line change
@@ -824,4 +824,35 @@ describe('Component slot', () => {
824824
expect(vm.$el.textContent).toBe('hello')
825825
}).then(done)
826826
})
827+
828+
it('should allow passing named slots as raw children down multiple layers of functional component', () => {
829+
const CompB = {
830+
functional: true,
831+
render (h, { slots }) {
832+
return slots().foo
833+
}
834+
}
835+
836+
const CompA = {
837+
functional: true,
838+
render (h, { children }) {
839+
return h(CompB, children)
840+
}
841+
}
842+
843+
const vm = new Vue({
844+
components: {
845+
CompA
846+
},
847+
template: `
848+
<div>
849+
<comp-a>
850+
<span slot="foo">foo</span>
851+
</comp-a>
852+
</div>
853+
`
854+
}).$mount()
855+
856+
expect(vm.$el.textContent).toBe('foo')
857+
})
827858
})

0 commit comments

Comments
 (0)