Skip to content

Commit ec903c7

Browse files
yyx990803aJean
authored andcommitted
fix(slots): properly handle nested named slot passing
fix vuejs#6996
1 parent 89945a1 commit ec903c7

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed

src/compiler/parser/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ function processSlot (el) {
467467
el.slotTarget = slotTarget === '""' ? '"default"' : slotTarget
468468
// preserve slot as an attribute for native shadow DOM compat
469469
// only for non-scoped slots.
470-
if (!el.slotScope) {
470+
if (el.tag !== 'template' && !el.slotScope) {
471471
addAttr(el, 'slot', slotTarget)
472472
}
473473
}

src/core/instance/render-helpers/render-slot.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export function renderSlot (
1212
bindObject: ?Object
1313
): ?Array<VNode> {
1414
const scopedSlotFn = this.$scopedSlots[name]
15+
let nodes
1516
if (scopedSlotFn) { // scoped slot
1617
props = props || {}
1718
if (bindObject) {
@@ -23,7 +24,7 @@ export function renderSlot (
2324
}
2425
props = extend(extend({}, bindObject), props)
2526
}
26-
return scopedSlotFn(props) || fallback
27+
nodes = scopedSlotFn(props) || fallback
2728
} else {
2829
const slotNodes = this.$slots[name]
2930
// warn duplicate slot usage
@@ -37,6 +38,13 @@ export function renderSlot (
3738
}
3839
slotNodes._rendered = true
3940
}
40-
return slotNodes || fallback
41+
nodes = slotNodes || fallback
42+
}
43+
44+
const target = props && props.slot
45+
if (target) {
46+
return this.$createElement('template', { slot: target }, nodes)
47+
} else {
48+
return nodes
4149
}
4250
}

src/core/instance/render-helpers/resolve-slots.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export function resolveSlots (
1111
if (!children) {
1212
return slots
1313
}
14-
const defaultSlot = []
1514
for (let i = 0, l = children.length; i < l; i++) {
1615
const child = children[i]
1716
const data = child.data
@@ -32,12 +31,14 @@ export function resolveSlots (
3231
slot.push(child)
3332
}
3433
} else {
35-
defaultSlot.push(child)
34+
(slots.default || (slots.default = [])).push(child)
3635
}
3736
}
38-
// ignore whitespace
39-
if (!defaultSlot.every(isWhitespace)) {
40-
slots.default = defaultSlot
37+
// ignore slots that contains only whitespace
38+
for (const name in slots) {
39+
if (slots[name].every(isWhitespace)) {
40+
delete slots[name]
41+
}
4142
}
4243
return slots
4344
}

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

+36
Original file line numberDiff line numberDiff line change
@@ -743,4 +743,40 @@ describe('Component slot', () => {
743743
}).$mount()
744744
expect(vm.$el.children[0].getAttribute('slot')).toBe('foo')
745745
})
746+
747+
it('passing a slot down as named slot', () => {
748+
const Bar = {
749+
template: `<div class="bar"><slot name="foo"/></div>`
750+
}
751+
752+
const Foo = {
753+
components: { Bar },
754+
template: `<div class="foo"><bar><slot slot="foo"/></bar></div>`
755+
}
756+
757+
const vm = new Vue({
758+
components: { Foo },
759+
template: `<div><foo>hello</foo></div>`
760+
}).$mount()
761+
762+
expect(vm.$el.innerHTML).toBe('<div class="foo"><div class="bar">hello</div></div>')
763+
})
764+
765+
it('fallback content for named template slot', () => {
766+
const Bar = {
767+
template: `<div class="bar"><slot name="foo">fallback</slot></div>`
768+
}
769+
770+
const Foo = {
771+
components: { Bar },
772+
template: `<div class="foo"><bar><template slot="foo"/><slot/></template></bar></div>`
773+
}
774+
775+
const vm = new Vue({
776+
components: { Foo },
777+
template: `<div><foo></foo></div>`
778+
}).$mount()
779+
780+
expect(vm.$el.innerHTML).toBe('<div class="foo"><div class="bar">fallback</div></div>')
781+
})
746782
})

0 commit comments

Comments
 (0)