]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: add test
authordaiwei <daiwei521@126.com>
Thu, 8 May 2025 09:13:54 +0000 (17:13 +0800)
committerdaiwei <daiwei521@126.com>
Fri, 9 May 2025 00:34:23 +0000 (08:34 +0800)
packages/runtime-core/src/renderer.ts
packages/runtime-dom/__tests__/customElement.spec.ts
packages/runtime-dom/src/apiCustomElement.ts

index e77f624c4f674a29c2e3f3c9de94237f2568e55f..d75efb890cd99fc6fefaad1649c5203e1b3d83ba 100644 (file)
@@ -966,9 +966,7 @@ function baseCreateRenderer(
           !isSameVNodeType(oldVNode, newVNode) ||
           // - In the case of a component, it could contain anything.
           oldVNode.shapeFlag & (ShapeFlags.COMPONENT | ShapeFlags.TELEPORT))
-          ? oldVNode.el._parentNode && !oldVNode.el.isConnected
-            ? oldVNode.el._parentNode
-            : hostParentNode(oldVNode.el)!
+          ? hostParentNode(oldVNode.el) || oldVNode.el._parentNode
           : // In other cases, the parent container is not actually used so we
             // just pass the block element here to avoid a DOM parentNode call.
             fallbackContainer
index fa14f6d48f79fc5f788350209f3a8d3f62f03cef..85f1d0820aa527c6ab7736864521ba6af1cc3f79 100644 (file)
@@ -9,6 +9,8 @@ import {
   createCommentVNode,
   createElementBlock,
   createElementVNode,
+  createSlots,
+  createTextVNode,
   defineAsyncComponent,
   defineComponent,
   defineCustomElement,
@@ -1138,8 +1140,8 @@ describe('defineCustomElement', () => {
       app.unmount()
     })
 
-    //#13206
-    test('should update slotted children correctly w/ shadowRoot false', async () => {
+    // #13206
+    test('update slotted v-if nodes w/ shadowRoot false', async () => {
       const E = defineCustomElement(
         defineComponent({
           props: {
@@ -1148,7 +1150,7 @@ describe('defineCustomElement', () => {
           render() {
             return this.isShown
               ? h('div', { key: 0 }, [renderSlot(this.$slots, 'default')])
-              : null
+              : createCommentVNode('v-if')
           },
         }),
         { shadowRoot: false },
@@ -1202,7 +1204,7 @@ describe('defineCustomElement', () => {
       const app = createApp(App)
       app.mount(container)
       expect(container.innerHTML).toBe(
-        `<ce-shadow-root-false data-v-app=""><!----></ce-shadow-root-false>`,
+        `<ce-shadow-root-false data-v-app=""><!--v-if--></ce-shadow-root-false>`,
       )
 
       click()
@@ -1214,7 +1216,7 @@ describe('defineCustomElement', () => {
       click()
       await nextTick()
       expect(container.innerHTML).toBe(
-        `<ce-shadow-root-false data-v-app=""><!----></ce-shadow-root-false>`,
+        `<ce-shadow-root-false data-v-app=""><!--v-if--></ce-shadow-root-false>`,
       )
 
       click()
@@ -1223,6 +1225,92 @@ describe('defineCustomElement', () => {
         `<ce-shadow-root-false data-v-app="" is-shown=""><div><div>true</div><div>hi</div></div></ce-shadow-root-false>`,
       )
     })
+
+    // #13234
+    test('switch between slotted and fallback nodes w/ shadowRoot false', async () => {
+      const E = defineCustomElement(
+        defineComponent({
+          render() {
+            return renderSlot(this.$slots, 'foo', {}, () => [
+              createTextVNode('fallback'),
+            ])
+          },
+        }),
+        { shadowRoot: false },
+      )
+      customElements.define('ce-with-fallback-shadow-root-false', E)
+
+      const Comp = defineComponent({
+        render() {
+          return (
+            openBlock(),
+            createElementBlock('ce-with-fallback-shadow-root-false', null, [
+              this.$slots.foo
+                ? (openBlock(),
+                  createElementBlock('div', { key: 0, slot: 'foo' }, [
+                    renderSlot(this.$slots, 'foo'),
+                  ]))
+                : createCommentVNode('v-if', true),
+              renderSlot(this.$slots, 'default'),
+            ])
+          )
+        },
+      })
+
+      const isShown = ref(false)
+      const App = defineComponent({
+        components: { Comp },
+        render() {
+          return (
+            openBlock(),
+            createBlock(
+              Comp,
+              null,
+              createSlots(
+                { _: 2 /* DYNAMIC */ } as any,
+                [
+                  isShown.value
+                    ? {
+                        name: 'foo',
+                        fn: withCtx(() => [createTextVNode('foo')]),
+                        key: '0',
+                      }
+                    : undefined,
+                ] as any,
+              ),
+              1024 /* DYNAMIC_SLOTS */,
+            )
+          )
+        },
+      })
+
+      const container = document.createElement('div')
+      document.body.appendChild(container)
+
+      const app = createApp(App)
+      app.mount(container)
+      expect(container.innerHTML).toBe(
+        `<ce-with-fallback-shadow-root-false data-v-app="">` +
+          `fallback` +
+          `</ce-with-fallback-shadow-root-false>`,
+      )
+
+      isShown.value = true
+      await nextTick()
+      expect(container.innerHTML).toBe(
+        `<ce-with-fallback-shadow-root-false data-v-app="">` +
+          `<div slot="foo">foo</div>` +
+          `</ce-with-fallback-shadow-root-false>`,
+      )
+
+      isShown.value = false
+      await nextTick()
+      expect(container.innerHTML).toBe(
+        `<ce-with-fallback-shadow-root-false data-v-app="">` +
+          `fallback<!--v-if-->` +
+          `</ce-with-fallback-shadow-root-false>`,
+      )
+    })
   })
 
   describe('helpers', () => {
index 41d4dc503079b9ad142b04cab58e81dba9c6822d..c5f3c9e341c4c88f95c0e212454e51189c5d541a 100644 (file)
@@ -337,6 +337,9 @@ export class VueElement
         this._app && this._app.unmount()
         if (this._instance) this._instance.ce = undefined
         this._app = this._instance = null
+        this._slots = undefined
+        this._slotFallbacks = undefined
+        this._slotAnchors = undefined
       }
     })
   }
@@ -692,7 +695,10 @@ export class VueElement
     for (let i = 0; i < prevNodes.length; i++) {
       const prevNode = prevNodes[i]
       const newNode = newNodes[i]
-      if (isComment(prevNode, 'v-if') || isComment(newNode, 'v-if')) {
+      if (
+        prevNode !== newNode &&
+        (isComment(prevNode, 'v-if') || isComment(newNode, 'v-if'))
+      ) {
         Object.keys(this._slots!).forEach(name => {
           const slotNodes = this._slots![name]
           if (slotNodes) {