Jelajahi Sumber

Merge branch 'minor' into edison/feat/teleportUseMoveBefore

edison 3 bulan lalu
induk
melakukan
9c28eda74d

+ 5 - 4
packages/runtime-core/src/renderer.ts

@@ -1460,7 +1460,7 @@ function baseCreateRenderer(
       if (!instance.isMounted) {
         let vnodeHook: VNodeHook | null | undefined
         const { el, props } = initialVNode
-        const { bm, m, parent, root, type } = instance
+        const { bm, parent, root, type } = instance
         const isAsyncWrapperVNode = isAsyncWrapper(initialVNode)
 
         toggleRecurse(instance, false)
@@ -1555,9 +1555,10 @@ function baseCreateRenderer(
           }
           initialVNode.el = subTree.el
         }
-        // mounted hook
-        if (m) {
-          queuePostRenderEffect(m, undefined, parentSuspense)
+        // Mounted hooks may be added to `instance.m` while mounting.
+        // Reading `instance.m` here ensures those hooks are still scheduled.
+        if (instance.m) {
+          queuePostRenderEffect(instance.m, undefined, parentSuspense)
         }
         // onVnodeMounted
         if (

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

@@ -28,6 +28,7 @@ import {
   child,
   createComponent,
   createDynamicComponent,
+  createSlot,
   defineVaporAsyncComponent,
   defineVaporComponent,
   renderEffect,
@@ -127,6 +128,84 @@ describe('vdomInterop', () => {
       await nextTick()
       expect(html()).toBe('<h1>bar</h1><input>')
     })
+
+    test('slot v-model should persist when switching vapor/vdom child', async () => {
+      const VaporComp1 = defineVaporComponent({
+        name: 'VaporComp1',
+        setup() {
+          return [document.createTextNode('comp1: '), createSlot('default')]
+        },
+      })
+
+      const VDomComp2 = defineComponent({
+        name: 'VDomComp2',
+        setup(_, { slots }) {
+          return () =>
+            h('div', [
+              'comp2: ',
+              // vdom <slot/>
+              renderSlot(slots, 'default'),
+            ])
+        },
+      })
+
+      const VaporParent = defineVaporComponent({
+        name: 'VaporParent',
+        props: {
+          show: Boolean,
+          modelValue: {},
+          modelModifiers: {},
+        },
+        emits: ['update:modelValue'],
+        setup(__props) {
+          const modelValue = useModel(__props, 'modelValue')
+          return createDynamicComponent(
+            () => (__props.show ? VaporComp1 : VDomComp2),
+            null,
+            {
+              default: () => {
+                const input = template('<input>')() as any
+                applyTextModel(
+                  input,
+                  () => modelValue.value,
+                  _value => (modelValue.value = _value),
+                )
+                return input
+              },
+            },
+            true,
+          )
+        },
+      })
+
+      const show = ref(true)
+      const msg = ref('')
+
+      const { host } = define({
+        setup() {
+          return () =>
+            h(VaporParent as any, {
+              show: show.value,
+              modelValue: msg.value,
+              'onUpdate:modelValue': (value: string) => {
+                msg.value = value
+              },
+            })
+        },
+      }).render()
+
+      const input1 = host.querySelector('input')!
+      input1.value = 'hello'
+      input1.dispatchEvent(new Event('input'))
+      await nextTick()
+      expect(msg.value).toBe('hello')
+
+      show.value = false
+      await nextTick()
+
+      const input2 = host.querySelector('input')!
+      expect(input2.value).toBe('hello')
+    })
   })
 
   describe('emit', () => {