Skip to content

Commit 5d52262

Browse files
committed
feat(core): expose all slots on $scopedSlots as functions
After this change, users using render functions can always make use of slots via `this.$scopedSlots` without worrying about whether the slot is being passed in as scoped or not. This should also make it easier to migrate to 3.0 where all slots are exposed as functions that return Array of VNodes on `this.$slots`.
1 parent 7988a55 commit 5d52262

File tree

5 files changed

+43
-9
lines changed

5 files changed

+43
-9
lines changed

src/core/instance/render-helpers/resolve-slots.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* @flow */
22

33
import type VNode from 'core/vdom/vnode'
4+
import { emptyObject } from 'core/util/index'
45

56
/**
67
* Runtime helper for resolving raw children VNodes into a slot object.
@@ -9,10 +10,10 @@ export function resolveSlots (
910
children: ?Array<VNode>,
1011
context: ?Component
1112
): { [key: string]: Array<VNode> } {
12-
const slots = {}
13-
if (!children) {
14-
return slots
13+
if (!children || !children.length) {
14+
return emptyObject
1515
}
16+
const slots = {}
1617
for (let i = 0, l = children.length; i < l; i++) {
1718
const child = children[i]
1819
const data = child.data

src/core/instance/render.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ export function renderMixin (Vue: Class<Component>) {
6464
const { render, _parentVnode } = vm.$options
6565

6666
if (_parentVnode) {
67-
vm.$scopedSlots = normalizeScopedSlots(_parentVnode.data.scopedSlots)
67+
vm.$scopedSlots = normalizeScopedSlots(
68+
_parentVnode.data.scopedSlots,
69+
vm.$slots
70+
)
6871
}
6972

7073
// set parent vnode. this allows render functions to have access

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export function FunctionalRenderContext (
5757
this.$options = options
5858
// pre-resolve slots for renderSlot()
5959
this.$slots = this.slots()
60-
this.$scopedSlots = normalizeScopedSlots(data.scopedSlots)
60+
this.$scopedSlots = normalizeScopedSlots(data.scopedSlots, this.$slots)
6161
}
6262

6363
if (options._scopeId) {

src/core/vdom/helpers/normalize-scoped-slots.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,31 @@
22

33
import { emptyObject } from 'core/util/index'
44

5-
export function normalizeScopedSlots (slots: { [key: string]: Function } | void): any {
5+
export function normalizeScopedSlots (
6+
slots: { [key: string]: Function } | void,
7+
normalSlots: { [key: string]: Array<VNode> }
8+
): any {
9+
let res
610
if (!slots) {
7-
return emptyObject
11+
if (normalSlots === emptyObject) {
12+
return emptyObject
13+
}
14+
res = {}
815
} else if (slots._normalized) {
916
return slots
1017
} else {
11-
const res = {}
18+
res = {}
1219
for (const key in slots) {
1320
res[key] = normalizeScopedSlot(slots[key])
1421
}
1522
res._normalized = true
16-
return res
1723
}
24+
if (normalSlots !== emptyObject) {
25+
for (const key in normalSlots) {
26+
res[key] = () => normalSlots[key]
27+
}
28+
}
29+
return res
1830
}
1931

2032
function normalizeScopedSlot(fn: Function) {

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

+18
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,24 @@ describe('Component scoped slot', () => {
455455
expect(vm.$el.outerHTML).toBe('<span>hello</span>')
456456
})
457457

458+
// new in 2.6, unifying all slots as functions
459+
it('non-scoped slots should also be available on $scopedSlots', () => {
460+
const vm = new Vue({
461+
template: `<foo>before <div slot="bar">{{ $slot.msg }}</div> after</foo>`,
462+
components: {
463+
foo: {
464+
render(h) {
465+
return h('div', [
466+
this.$scopedSlots.default(),
467+
this.$scopedSlots.bar({ msg: 'hi' })
468+
])
469+
}
470+
}
471+
}
472+
}).$mount()
473+
expect(vm.$el.innerHTML).toBe(`before after<div>hi</div>`)
474+
})
475+
458476
// #4779
459477
it('should support dynamic slot target', done => {
460478
const Child = {

0 commit comments

Comments
 (0)