Skip to content

Commit

Permalink
fix(slots): properly handle nested named slot passing
Browse files Browse the repository at this point in the history
fix #6996
  • Loading branch information
yyx990803 committed Nov 3, 2017
1 parent 4fe1a95 commit 5a9da95
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/compiler/parser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
12 changes: 10 additions & 2 deletions src/core/instance/render-helpers/render-slot.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
Expand All @@ -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
}
}
11 changes: 6 additions & 5 deletions src/core/instance/render-helpers/resolve-slots.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand Down
36 changes: 36 additions & 0 deletions test/unit/features/component/component-slot.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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>')
})
})

0 comments on commit 5a9da95

Please sign in to comment.