fix(slots): properly handle nested named slot passing

fix #6996
This commit is contained in:
Evan You 2017-11-03 16:45:54 -04:00
parent 4fe1a95d29
commit 5a9da95b8a
4 changed files with 53 additions and 8 deletions

View File

@ -467,7 +467,7 @@ function processSlot (el) {
el.slotTarget = slotTarget === '""' ? '"default"' : slotTarget
// preserve slot as an attribute for native shadow DOM compat
// only for non-scoped slots.
if (!el.slotScope) {
if (el.tag !== 'template' && !el.slotScope) {
addAttr(el, 'slot', slotTarget)
}
}

View File

@ -12,6 +12,7 @@ export function renderSlot (
bindObject: ?Object
): ?Array<VNode> {
const scopedSlotFn = this.$scopedSlots[name]
let nodes
if (scopedSlotFn) { // scoped slot
props = props || {}
if (bindObject) {
@ -23,7 +24,7 @@ export function renderSlot (
}
props = extend(extend({}, bindObject), props)
}
return scopedSlotFn(props) || fallback
nodes = scopedSlotFn(props) || fallback
} else {
const slotNodes = this.$slots[name]
// warn duplicate slot usage
@ -37,6 +38,13 @@ export function renderSlot (
}
slotNodes._rendered = true
}
return slotNodes || fallback
nodes = slotNodes || fallback
}
const target = props && props.slot
if (target) {
return this.$createElement('template', { slot: target }, nodes)
} else {
return nodes
}
}

View File

@ -11,7 +11,6 @@ export function resolveSlots (
if (!children) {
return slots
}
const defaultSlot = []
for (let i = 0, l = children.length; i < l; i++) {
const child = children[i]
const data = child.data
@ -32,12 +31,14 @@ export function resolveSlots (
slot.push(child)
}
} else {
defaultSlot.push(child)
(slots.default || (slots.default = [])).push(child)
}
}
// ignore whitespace
if (!defaultSlot.every(isWhitespace)) {
slots.default = defaultSlot
// ignore slots that contains only whitespace
for (const name in slots) {
if (slots[name].every(isWhitespace)) {
delete slots[name]
}
}
return slots
}

View File

@ -743,4 +743,40 @@ describe('Component slot', () => {
}).$mount()
expect(vm.$el.children[0].getAttribute('slot')).toBe('foo')
})
it('passing a slot down as named slot', () => {
const Bar = {
template: `<div class="bar"><slot name="foo"/></div>`
}
const Foo = {
components: { Bar },
template: `<div class="foo"><bar><slot slot="foo"/></bar></div>`
}
const vm = new Vue({
components: { Foo },
template: `<div><foo>hello</foo></div>`
}).$mount()
expect(vm.$el.innerHTML).toBe('<div class="foo"><div class="bar">hello</div></div>')
})
it('fallback content for named template slot', () => {
const Bar = {
template: `<div class="bar"><slot name="foo">fallback</slot></div>`
}
const Foo = {
components: { Bar },
template: `<div class="foo"><bar><template slot="foo"/><slot/></template></bar></div>`
}
const vm = new Vue({
components: { Foo },
template: `<div><foo></foo></div>`
}).$mount()
expect(vm.$el.innerHTML).toBe('<div class="foo"><div class="bar">fallback</div></div>')
})
})