diff --git a/src/core/vdom/helpers/normalize-scoped-slots.js b/src/core/vdom/helpers/normalize-scoped-slots.js index fcb2fcbfb25..e4197428d82 100644 --- a/src/core/vdom/helpers/normalize-scoped-slots.js +++ b/src/core/vdom/helpers/normalize-scoped-slots.js @@ -1,5 +1,6 @@ /* @flow */ +import { hasOwn } from 'shared/util' import { normalizeChildren } from 'core/vdom/helpers/normalize-children' export function normalizeScopedSlots ( @@ -15,7 +16,7 @@ export function normalizeScopedSlots ( res = {} for (const key in slots) { if (slots[key] && key[0] !== '$') { - res[key] = normalizeScopedSlot(slots[key]) + res[key] = normalizeScopedSlot(normalSlots, key, slots[key]) } } } @@ -30,13 +31,20 @@ export function normalizeScopedSlots ( return res } -function normalizeScopedSlot(fn: Function): Function { - return scope => { +function normalizeScopedSlot(normalSlots, key, fn) { + const normalized = (scope = {}) => { const res = fn(scope) return res && typeof res === 'object' && !Array.isArray(res) ? [res] // single vnode : normalizeChildren(res) } + // proxy scoped slots on normal $slots + if (!hasOwn(normalSlots, key)) { + Object.defineProperty(normalSlots, key, { + get: normalized + }) + } + return normalized } function proxyNormalSlot(slots, key) { diff --git a/test/unit/features/component/component-scoped-slot.spec.js b/test/unit/features/component/component-scoped-slot.spec.js index 18264db98fc..7c6caf26390 100644 --- a/test/unit/features/component/component-scoped-slot.spec.js +++ b/test/unit/features/component/component-scoped-slot.spec.js @@ -456,7 +456,7 @@ describe('Component scoped slot', () => { }) // new in 2.6, unifying all slots as functions - it('non-scoped slots should also be available on $scopedSlots', () => { + it('non-scoped slots should also be available on this.$scopedSlots', () => { const vm = new Vue({ template: `before
{{ scope.msg }}
after
`, components: { @@ -473,6 +473,24 @@ describe('Component scoped slot', () => { expect(vm.$el.innerHTML).toBe(`before after
hi
`) }) + // #9421 the other side of unification is also needed + // for library authors + it('scoped slots should also be available on this.$slots', () => { + const Child = { + render: function (h) { + return h( + 'div', + this.$slots.content + ) + } + } + const vm = new Vue({ + template: ``, + components: { Child } + }).$mount() + expect(vm.$el.innerHTML).toBe(`foo`) + }) + // #4779 it('should support dynamic slot target', done => { const Child = {