diff --git a/src/core/instance/render-helpers/resolve-slots.js b/src/core/instance/render-helpers/resolve-slots.js index 34d8ce26..533b059c 100644 --- a/src/core/instance/render-helpers/resolve-slots.js +++ b/src/core/instance/render-helpers/resolve-slots.js @@ -1,6 +1,7 @@ /* @flow */ import type VNode from 'core/vdom/vnode' +import { emptyObject } from 'core/util/index' /** * Runtime helper for resolving raw children VNodes into a slot object. @@ -9,10 +10,10 @@ export function resolveSlots ( children: ?Array, context: ?Component ): { [key: string]: Array } { - const slots = {} - if (!children) { - return slots + if (!children || !children.length) { + return emptyObject } + const slots = {} for (let i = 0, l = children.length; i < l; i++) { const child = children[i] const data = child.data diff --git a/src/core/instance/render.js b/src/core/instance/render.js index 3139f81a..2b9c8d11 100644 --- a/src/core/instance/render.js +++ b/src/core/instance/render.js @@ -64,7 +64,10 @@ export function renderMixin (Vue: Class) { const { render, _parentVnode } = vm.$options if (_parentVnode) { - vm.$scopedSlots = normalizeScopedSlots(_parentVnode.data.scopedSlots) + vm.$scopedSlots = normalizeScopedSlots( + _parentVnode.data.scopedSlots, + vm.$slots + ) } // set parent vnode. this allows render functions to have access diff --git a/src/core/vdom/create-functional-component.js b/src/core/vdom/create-functional-component.js index 92ebe714..8b6888e4 100644 --- a/src/core/vdom/create-functional-component.js +++ b/src/core/vdom/create-functional-component.js @@ -57,7 +57,7 @@ export function FunctionalRenderContext ( this.$options = options // pre-resolve slots for renderSlot() this.$slots = this.slots() - this.$scopedSlots = normalizeScopedSlots(data.scopedSlots) + this.$scopedSlots = normalizeScopedSlots(data.scopedSlots, this.$slots) } if (options._scopeId) { diff --git a/src/core/vdom/helpers/normalize-scoped-slots.js b/src/core/vdom/helpers/normalize-scoped-slots.js index d58a6c62..3672d7e7 100644 --- a/src/core/vdom/helpers/normalize-scoped-slots.js +++ b/src/core/vdom/helpers/normalize-scoped-slots.js @@ -2,19 +2,31 @@ import { emptyObject } from 'core/util/index' -export function normalizeScopedSlots (slots: { [key: string]: Function } | void): any { +export function normalizeScopedSlots ( + slots: { [key: string]: Function } | void, + normalSlots: { [key: string]: Array } +): any { + let res if (!slots) { - return emptyObject + if (normalSlots === emptyObject) { + return emptyObject + } + res = {} } else if (slots._normalized) { return slots } else { - const res = {} + res = {} for (const key in slots) { res[key] = normalizeScopedSlot(slots[key]) } res._normalized = true - return res } + if (normalSlots !== emptyObject) { + for (const key in normalSlots) { + res[key] = () => normalSlots[key] + } + } + return res } function normalizeScopedSlot(fn: Function) { diff --git a/test/unit/features/component/component-scoped-slot.spec.js b/test/unit/features/component/component-scoped-slot.spec.js index aa9e12cb..f633d0dc 100644 --- a/test/unit/features/component/component-scoped-slot.spec.js +++ b/test/unit/features/component/component-scoped-slot.spec.js @@ -455,6 +455,24 @@ describe('Component scoped slot', () => { expect(vm.$el.outerHTML).toBe('hello') }) + // new in 2.6, unifying all slots as functions + it('non-scoped slots should also be available on $scopedSlots', () => { + const vm = new Vue({ + template: `before
{{ $slot.msg }}
after
`, + components: { + foo: { + render(h) { + return h('div', [ + this.$scopedSlots.default(), + this.$scopedSlots.bar({ msg: 'hi' }) + ]) + } + } + } + }).$mount() + expect(vm.$el.innerHTML).toBe(`before after
hi
`) + }) + // #4779 it('should support dynamic slot target', done => { const Child = {