Jelajahi Sumber

fix: fix scopedSlots regression

Evan You 3 tahun lalu
induk
melakukan
4f2a04e6a8

+ 2 - 1
src/core/instance/render.ts

@@ -102,7 +102,8 @@ export function renderMixin(Vue: typeof Component) {
       vm.$scopedSlots = normalizeScopedSlots(
         vm.$parent!,
         _parentVnode.data!.scopedSlots,
-        vm.$slots
+        vm.$slots,
+        vm.$scopedSlots
       )
       if (vm._slotsProxy) {
         syncSetupSlots(vm._slotsProxy, vm.$scopedSlots)

+ 23 - 18
src/core/vdom/helpers/normalize-scoped-slots.ts

@@ -8,35 +8,40 @@ import { currentInstance, setCurrentInstance } from 'v3/currentInstance'
 
 export function normalizeScopedSlots(
   ownerVm: Component,
-  slots: { [key: string]: Function } | void,
-  normalSlots: { [key: string]: VNode[] }
+  scopedSlots: { [key: string]: Function } | undefined,
+  normalSlots: { [key: string]: VNode[] },
+  prevScopedSlots?: { [key: string]: Function }
 ): any {
   let res
-  const prevSlots = ownerVm.$scopedSlots
   const hasNormalSlots = Object.keys(normalSlots).length > 0
-  const isStable = slots ? !!slots.$stable : !hasNormalSlots
-  const key = slots && slots.$key
-  if (!slots) {
+  const isStable = scopedSlots ? !!scopedSlots.$stable : !hasNormalSlots
+  const key = scopedSlots && scopedSlots.$key
+  if (!scopedSlots) {
     res = {}
-  } else if (slots._normalized) {
+  } else if (scopedSlots._normalized) {
     // fast path 1: child component re-render only, parent did not change
-    return slots._normalized
+    return scopedSlots._normalized
   } else if (
     isStable &&
-    prevSlots &&
-    prevSlots !== emptyObject &&
-    key === prevSlots.$key &&
+    prevScopedSlots &&
+    prevScopedSlots !== emptyObject &&
+    key === prevScopedSlots.$key &&
     !hasNormalSlots &&
-    !prevSlots.$hasNormal
+    !prevScopedSlots.$hasNormal
   ) {
     // fast path 2: stable scoped slots w/ no normal slots to proxy,
     // only need to normalize once
-    return prevSlots
+    return prevScopedSlots
   } else {
     res = {}
-    for (const key in slots) {
-      if (slots[key] && key[0] !== '$') {
-        res[key] = normalizeScopedSlot(ownerVm, normalSlots, key, slots[key])
+    for (const key in scopedSlots) {
+      if (scopedSlots[key] && key[0] !== '$') {
+        res[key] = normalizeScopedSlot(
+          ownerVm,
+          normalSlots,
+          key,
+          scopedSlots[key]
+        )
       }
     }
   }
@@ -48,8 +53,8 @@ export function normalizeScopedSlots(
   }
   // avoriaz seems to mock a non-extensible $scopedSlots object
   // and when that is passed down this would cause an error
-  if (slots && Object.isExtensible(slots)) {
-    slots._normalized = res
+  if (scopedSlots && Object.isExtensible(scopedSlots)) {
+    scopedSlots._normalized = res
   }
   def(res, '$stable', isStable)
   def(res, '$key', key)

+ 29 - 0
test/unit/features/component/component-slot.spec.ts

@@ -1044,4 +1044,33 @@ describe('Component slot', () => {
 
     expect(vm.$el.innerHTML).toBe(`<!----><span>b</span>`)
   })
+
+  // regression 2.7.0-alpha.4
+  it('passing scoped slots through nested parent chain', () => {
+    const Foo = {
+      template: `
+        <div><slot>foo default</slot></div>
+      `
+    }
+
+    const Bar = {
+      components: { Foo },
+      template: `<Foo><slot name="bar"/></Foo>`
+    }
+
+    const App = {
+      components: { Bar },
+      template: `<Bar>
+        <template #bar>
+          <span>App content for Bar#bar</span>
+        </template>
+      </Bar>`
+    }
+
+    const vm = new Vue({
+      render: h => h(App)
+    }).$mount()
+
+    expect(vm.$el.innerHTML).toMatch(`App content for Bar#bar`)
+  })
 })