]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): force diff slot fallback content and provided content
authorEvan You <evan@vuejs.org>
Fri, 12 Jul 2024 10:22:31 +0000 (18:22 +0800)
committerEvan You <evan@vuejs.org>
Fri, 12 Jul 2024 10:26:11 +0000 (18:26 +0800)
fix #7256
fix #9200
fix #9308

close #7266
close #9213

packages/runtime-core/__tests__/helpers/renderSlot.spec.ts
packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts
packages/runtime-core/src/helpers/renderSlot.ts

index b6183ac3c3677a7f770e0cf5dc130c558f5405fa..c4ae077ba347e79e461e6b1b0c34e247c6444704 100644 (file)
@@ -26,13 +26,17 @@ describe('renderSlot', () => {
     const vnode = renderSlot(
       { default: () => [(child = h('child'))] },
       'default',
+      { key: 'foo' },
     )
     expect(vnode.children).toEqual([child])
+    expect(vnode.key).toBe('foo')
   })
 
   it('should render slot fallback', () => {
-    const vnode = renderSlot({}, 'default', {}, () => ['fallback'])
+    const vnode = renderSlot({}, 'default', { key: 'foo' }, () => ['fallback'])
     expect(vnode.children).toEqual(['fallback'])
+    // should attach fallback key postfix
+    expect(vnode.key).toBe('foo_fb')
   })
 
   it('should warn render ssr slot', () => {
index dceda28fcae868ed3f0e429a49053b6d61903c54..7abd94e196090d311ffb4148dadd055d11f658c1 100644 (file)
@@ -1105,4 +1105,77 @@ describe('renderer: optimized mode', () => {
       expect(app.config.errorHandler).not.toHaveBeenCalled()
     }
   })
+
+  test('diff slot and slot fallback node', async () => {
+    const Comp = {
+      props: ['show'],
+      setup(props: any, { slots }: SetupContext) {
+        return () => {
+          return (
+            openBlock(),
+            createElementBlock('div', null, [
+              renderSlot(slots, 'default', { hide: !props.show }, () => [
+                (openBlock(),
+                (block = createElementBlock(
+                  Fragment,
+                  { key: 0 },
+                  [createTextVNode('foo')],
+                  PatchFlags.STABLE_FRAGMENT,
+                ))),
+              ]),
+            ])
+          )
+        }
+      },
+    }
+
+    const show = ref(true)
+    const app = createApp({
+      render() {
+        return (
+          openBlock(),
+          createBlock(
+            Comp,
+            { show: show.value },
+            {
+              default: withCtx(({ hide }: { hide: boolean }) => [
+                !hide
+                  ? (openBlock(),
+                    createElementBlock(
+                      Fragment,
+                      { key: 0 },
+                      [
+                        createCommentVNode('comment'),
+                        createElementVNode(
+                          'div',
+                          null,
+                          'bar',
+                          PatchFlags.HOISTED,
+                        ),
+                      ],
+                      PatchFlags.STABLE_FRAGMENT,
+                    ))
+                  : createCommentVNode('v-if', true),
+              ]),
+              _: SlotFlags.STABLE,
+            },
+            PatchFlags.PROPS,
+            ['show'],
+          )
+        )
+      },
+    })
+
+    app.mount(root)
+    expect(inner(root)).toBe('<div><!--comment--><div>bar</div></div>')
+    expect(block).toBe(null)
+
+    show.value = false
+    await nextTick()
+    expect(inner(root)).toBe('<div>foo</div>')
+
+    show.value = true
+    await nextTick()
+    expect(inner(root)).toBe('<div><!--comment--><div>bar</div></div>')
+  })
 })
index 8a7608219d9d1dbdf05b54d0ca15de089ab1572f..f0b13904f08838db5983035985799158966cf78c 100644 (file)
@@ -65,11 +65,13 @@ export function renderSlot(
     Fragment,
     {
       key:
-        props.key ||
-        // slot content array of a dynamic conditional slot may have a branch
-        // key attached in the `createSlots` helper, respect that
-        (validSlotContent && (validSlotContent as any).key) ||
-        `_${name}`,
+        (props.key ||
+          // slot content array of a dynamic conditional slot may have a branch
+          // key attached in the `createSlots` helper, respect that
+          (validSlotContent && (validSlotContent as any).key) ||
+          `_${name}`) +
+        // #7256 force differentiate fallback content from actual content
+        (!validSlotContent && fallback ? '_fb' : ''),
     },
     validSlotContent || (fallback ? fallback() : []),
     validSlotContent && (slots as RawSlots)._ === SlotFlags.STABLE