Explorar el Código

feat: expose all scoped slots on this.$slots

close #9421
Evan You hace 7 años
padre
commit
0129b0eb12

+ 11 - 3
src/core/vdom/helpers/normalize-scoped-slots.js

@@ -1,5 +1,6 @@
 /* @flow */
 /* @flow */
 
 
+import { hasOwn } from 'shared/util'
 import { normalizeChildren } from 'core/vdom/helpers/normalize-children'
 import { normalizeChildren } from 'core/vdom/helpers/normalize-children'
 
 
 export function normalizeScopedSlots (
 export function normalizeScopedSlots (
@@ -15,7 +16,7 @@ export function normalizeScopedSlots (
     res = {}
     res = {}
     for (const key in slots) {
     for (const key in slots) {
       if (slots[key] && key[0] !== '$') {
       if (slots[key] && key[0] !== '$') {
-        res[key] = normalizeScopedSlot(slots[key])
+        res[key] = normalizeScopedSlot(normalSlots, key, slots[key])
       }
       }
     }
     }
   }
   }
@@ -30,13 +31,20 @@ export function normalizeScopedSlots (
   return res
   return res
 }
 }
 
 
-function normalizeScopedSlot(fn: Function): Function {
-  return scope => {
+function normalizeScopedSlot(normalSlots, key, fn) {
+  const normalized = (scope = {}) => {
     const res = fn(scope)
     const res = fn(scope)
     return res && typeof res === 'object' && !Array.isArray(res)
     return res && typeof res === 'object' && !Array.isArray(res)
       ? [res] // single vnode
       ? [res] // single vnode
       : normalizeChildren(res)
       : normalizeChildren(res)
   }
   }
+  // proxy scoped slots on normal $slots
+  if (!hasOwn(normalSlots, key)) {
+    Object.defineProperty(normalSlots, key, {
+      get: normalized
+    })
+  }
+  return normalized
 }
 }
 
 
 function proxyNormalSlot(slots, key) {
 function proxyNormalSlot(slots, key) {

+ 19 - 1
test/unit/features/component/component-scoped-slot.spec.js

@@ -456,7 +456,7 @@ describe('Component scoped slot', () => {
   })
   })
 
 
   // new in 2.6, unifying all slots as functions
   // new in 2.6, unifying all slots as functions
-  it('non-scoped slots should also be available on $scopedSlots', () => {
+  it('non-scoped slots should also be available on this.$scopedSlots', () => {
     const vm = new Vue({
     const vm = new Vue({
       template: `<foo>before <div slot="bar" slot-scope="scope">{{ scope.msg }}</div> after</foo>`,
       template: `<foo>before <div slot="bar" slot-scope="scope">{{ scope.msg }}</div> after</foo>`,
       components: {
       components: {
@@ -473,6 +473,24 @@ describe('Component scoped slot', () => {
     expect(vm.$el.innerHTML).toBe(`before  after<div>hi</div>`)
     expect(vm.$el.innerHTML).toBe(`before  after<div>hi</div>`)
   })
   })
 
 
+  // #9421 the other side of unification is also needed
+  // for library authors
+  it('scoped slots should also be available on this.$slots', () => {
+    const Child = {
+      render: function (h) {
+        return h(
+          'div',
+          this.$slots.content
+        )
+      }
+    }
+    const vm = new Vue({
+      template: `<child><template #content>foo</template></child>`,
+      components: { Child }
+    }).$mount()
+    expect(vm.$el.innerHTML).toBe(`foo`)
+  })
+
   // #4779
   // #4779
   it('should support dynamic slot target', done => {
   it('should support dynamic slot target', done => {
     const Child = {
     const Child = {