Răsfoiți Sursa

fix(slots): properly handle nested named slot passing

fix #6996
Evan You 8 ani în urmă
părinte
comite
5a9da95b8a

+ 1 - 1
src/compiler/parser/index.js

@@ -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)
       }
     }

+ 10 - 2
src/core/instance/render-helpers/render-slot.js

@@ -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
   }
 }

+ 6 - 5
src/core/instance/render-helpers/resolve-slots.js

@@ -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
 }

+ 36 - 0
test/unit/features/component/component-slot.spec.js

@@ -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>')
+  })
 })