]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-vapor): handle v-model vdom interop error (#13643)
authoredison <daiwei521@126.com>
Fri, 18 Jul 2025 09:34:50 +0000 (17:34 +0800)
committerGitHub <noreply@github.com>
Fri, 18 Jul 2025 09:34:50 +0000 (17:34 +0800)
packages/runtime-core/src/renderer.ts
packages/runtime-vapor/__tests__/vdomInterop.spec.ts

index bad40f14393292b9443de30996946f86a31192b1..30f9e6b2c1f08838ae929761e80f823d46dad88a 100644 (file)
@@ -2727,7 +2727,7 @@ export function traverseStaticChildren(
 function locateNonHydratedAsyncRoot(
   instance: ComponentInternalInstance,
 ): ComponentInternalInstance | undefined {
-  const subComponent = instance.subTree.component
+  const subComponent = instance.vapor ? null : instance.subTree.component
   if (subComponent) {
     if (subComponent.asyncDep && !subComponent.asyncResolved) {
       return subComponent
index 96222e6ee0b5fbc5be10cf1bf901a25b46ead036..98c4cdbc9d03186bcc2a3addbb3dc483dc79e0e4 100644 (file)
@@ -1,6 +1,23 @@
-import { createVNode, defineComponent, h, renderSlot } from '@vue/runtime-dom'
+import {
+  createVNode,
+  defineComponent,
+  h,
+  nextTick,
+  ref,
+  renderSlot,
+  toDisplayString,
+  useModel,
+} from '@vue/runtime-dom'
 import { makeInteropRender } from './_utils'
-import { createComponent, defineVaporComponent } from '../src'
+import {
+  applyTextModel,
+  child,
+  createComponent,
+  defineVaporComponent,
+  renderEffect,
+  setText,
+  template,
+} from '../src'
 
 const define = makeInteropRender()
 
@@ -26,6 +43,54 @@ describe('vdomInterop', () => {
     })
   })
 
+  describe('v-model', () => {
+    test('basic work', async () => {
+      const VaporChild = defineVaporComponent({
+        props: {
+          modelValue: {},
+          modelModifiers: {},
+        },
+        emits: ['update:modelValue'],
+        setup(__props) {
+          const modelValue = useModel(__props, 'modelValue')
+
+          const n0 = template('<h1> </h1>')() as any
+          const n1 = template('<input>')() as any
+          const x0 = child(n0) as any
+          applyTextModel(
+            n1,
+            () => modelValue.value,
+            _value => (modelValue.value = _value),
+          )
+          renderEffect(() => setText(x0, toDisplayString(modelValue.value)))
+          return [n0, n1]
+        },
+      })
+
+      const { html, host } = define({
+        setup() {
+          const msg = ref('foo')
+          return () =>
+            h(VaporChild as any, {
+              modelValue: msg.value,
+              'onUpdate:modelValue': (value: string) => {
+                msg.value = value
+              },
+            })
+        },
+      }).render()
+
+      expect(html()).toBe('<h1>foo</h1><input>')
+
+      const inputEl = host.querySelector('input')!
+      inputEl.value = 'bar'
+      inputEl.dispatchEvent(new Event('input'))
+
+      await nextTick()
+      expect(html()).toBe('<h1>bar</h1><input>')
+    })
+  })
+
   describe('emit', () => {
     test('emit from vapor child to vdom parent', () => {
       const VaporChild = defineVaporComponent({