Explorar o código

fix(vapor): properly move vapor component / slot (#14363)

* fix(runtime-code): MoveFn is compatible with vapor block

* fix(vdomInterop): update move function to accept moveType parameter

---------

Co-authored-by: daiwei <daiwei521@126.com>
Jack hai 2 meses
pai
achega
b0c04eb6c2

+ 2 - 1
packages/runtime-core/src/apiCreateApp.ts

@@ -19,6 +19,7 @@ import type {
 import { type Directive, validateDirectiveName } from './directives'
 import type {
   ElementNamespace,
+  MoveType,
   RootRenderFunction,
   UnmountComponentFn,
 } from './renderer'
@@ -191,7 +192,7 @@ export interface VaporInteropInterface {
   ): GenericComponentInstance // VaporComponentInstance
   update(n1: VNode, n2: VNode, shouldUpdate: boolean): void
   unmount(vnode: VNode, doRemove?: boolean): void
-  move(vnode: VNode, container: any, anchor: any): void
+  move(vnode: VNode, container: any, anchor: any, moveType: MoveType): void
   slot(
     n1: VNode | null,
     n2: VNode,

+ 18 - 11
packages/runtime-core/src/renderer.ts

@@ -2202,18 +2202,25 @@ function baseCreateRenderer(
     parentSuspense = null,
   ) => {
     const { el, type, transition, children, shapeFlag } = vnode
+
+    if (isVaporComponent(type as ConcreteComponent) || type === VaporSlot) {
+      getVaporInterface(parentComponent, vnode).move(
+        vnode,
+        container,
+        anchor,
+        moveType,
+      )
+      return
+    }
+
     if (shapeFlag & ShapeFlags.COMPONENT) {
-      if (isVaporComponent(type as ConcreteComponent)) {
-        getVaporInterface(parentComponent, vnode).move(vnode, container, anchor)
-      } else {
-        move(
-          vnode.component!.subTree,
-          container,
-          anchor,
-          moveType,
-          parentComponent,
-        )
-      }
+      move(
+        vnode.component!.subTree,
+        container,
+        anchor,
+        moveType,
+        parentComponent,
+      )
       return
     }
 

+ 40 - 0
packages/runtime-vapor/__tests__/vdomInterop.spec.ts

@@ -28,6 +28,7 @@ import {
   child,
   createComponent,
   createDynamicComponent,
+  createIf,
   createSlot,
   defineVaporAsyncComponent,
   defineVaporComponent,
@@ -1219,5 +1220,44 @@ describe('vdomInterop', () => {
       expect(inputEl.value).toBe('vapor')
       assertHookCalls(hooks, [2, 2, 3, 2, 1])
     })
+
+    test('render vapor slot', async () => {
+      const show = ref(true)
+
+      const VDomComp = defineComponent({
+        setup(_, { slots }) {
+          return () => renderSlot(slots, 'default')
+        },
+      })
+      const App = defineVaporComponent({
+        setup() {
+          const n5 = createComponent(VaporKeepAlive, null, {
+            default: () =>
+              createIf(
+                () => show.value,
+                () =>
+                  createComponent(VDomComp as any, null, {
+                    default: () => template('slot text')(),
+                  }),
+              ),
+          })
+          return n5
+        },
+      })
+
+      const { html } = define({
+        setup() {
+          return () => h(App)
+        },
+      }).render()
+
+      expect(html()).toBe('slot text<!--if-->')
+      show.value = false
+      await nextTick()
+      expect(html()).toBe('<!--if-->')
+      show.value = true
+      await nextTick()
+      expect(html()).toBe('slot text<!--if-->')
+    })
   })
 })

+ 10 - 4
packages/runtime-vapor/src/vdomInterop.ts

@@ -48,7 +48,13 @@ import {
   mountComponent,
   unmountComponent,
 } from './component'
-import { type Block, type VaporTransitionHooks, insert, remove } from './block'
+import {
+  type Block,
+  type VaporTransitionHooks,
+  insert,
+  move,
+  remove,
+} from './block'
 import {
   EMPTY_OBJ,
   ShapeFlags,
@@ -213,9 +219,9 @@ const vaporInteropImpl: Omit<
     }
   },
 
-  move(vnode, container, anchor) {
-    insert(vnode.vb || (vnode.component as any), container, anchor)
-    insert(vnode.anchor as any, container, anchor)
+  move(vnode, container, anchor, moveType) {
+    move(vnode.vb || (vnode.component as any), container, anchor, moveType)
+    move(vnode.anchor as any, container, anchor, moveType)
   },
 
   hydrate(vnode, node, container, anchor, parentComponent, parentSuspense) {