Skip to content

Commit 0129b0e

Browse files
committed
feat: expose all scoped slots on this.$slots
close #9421
1 parent b034abf commit 0129b0e

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

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

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

3+
import { hasOwn } from 'shared/util'
34
import { normalizeChildren } from 'core/vdom/helpers/normalize-children'
45

56
export function normalizeScopedSlots (
@@ -15,7 +16,7 @@ export function normalizeScopedSlots (
1516
res = {}
1617
for (const key in slots) {
1718
if (slots[key] && key[0] !== '$') {
18-
res[key] = normalizeScopedSlot(slots[key])
19+
res[key] = normalizeScopedSlot(normalSlots, key, slots[key])
1920
}
2021
}
2122
}
@@ -30,13 +31,20 @@ export function normalizeScopedSlots (
3031
return res
3132
}
3233

33-
function normalizeScopedSlot(fn: Function): Function {
34-
return scope => {
34+
function normalizeScopedSlot(normalSlots, key, fn) {
35+
const normalized = (scope = {}) => {
3536
const res = fn(scope)
3637
return res && typeof res === 'object' && !Array.isArray(res)
3738
? [res] // single vnode
3839
: normalizeChildren(res)
3940
}
41+
// proxy scoped slots on normal $slots
42+
if (!hasOwn(normalSlots, key)) {
43+
Object.defineProperty(normalSlots, key, {
44+
get: normalized
45+
})
46+
}
47+
return normalized
4048
}
4149

4250
function proxyNormalSlot(slots, key) {

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

+19-1
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ describe('Component scoped slot', () => {
456456
})
457457

458458
// new in 2.6, unifying all slots as functions
459-
it('non-scoped slots should also be available on $scopedSlots', () => {
459+
it('non-scoped slots should also be available on this.$scopedSlots', () => {
460460
const vm = new Vue({
461461
template: `<foo>before <div slot="bar" slot-scope="scope">{{ scope.msg }}</div> after</foo>`,
462462
components: {
@@ -473,6 +473,24 @@ describe('Component scoped slot', () => {
473473
expect(vm.$el.innerHTML).toBe(`before after<div>hi</div>`)
474474
})
475475

476+
// #9421 the other side of unification is also needed
477+
// for library authors
478+
it('scoped slots should also be available on this.$slots', () => {
479+
const Child = {
480+
render: function (h) {
481+
return h(
482+
'div',
483+
this.$slots.content
484+
)
485+
}
486+
}
487+
const vm = new Vue({
488+
template: `<child><template #content>foo</template></child>`,
489+
components: { Child }
490+
}).$mount()
491+
expect(vm.$el.innerHTML).toBe(`foo`)
492+
})
493+
476494
// #4779
477495
it('should support dynamic slot target', done => {
478496
const Child = {

0 commit comments

Comments
 (0)