From 563840c18489ae73d725d872644903d265178617 Mon Sep 17 00:00:00 2001 From: Zhong Date: Thu, 2 Oct 2025 21:06:03 +0800 Subject: [PATCH 1/3] fix(v-model): number modifier should update input value --- .../runtime-dom/__tests__/directives/vModel.spec.ts | 3 +++ packages/runtime-dom/src/directives/vModel.ts | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/runtime-dom/__tests__/directives/vModel.spec.ts b/packages/runtime-dom/__tests__/directives/vModel.spec.ts index 534e5dfe98e..2e46eab6fc6 100644 --- a/packages/runtime-dom/__tests__/directives/vModel.spec.ts +++ b/packages/runtime-dom/__tests__/directives/vModel.spec.ts @@ -344,6 +344,9 @@ describe('vModel', () => { triggerEvent('input', number) await nextTick() expect(data.number).toEqual(1.2) + await nextTick() + triggerEvent('change', number) + expect(number.value).toEqual('1.2') trim.value = ' hello, world ' triggerEvent('input', trim) diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index 5057e16d472..448a9bd8e96 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -66,9 +66,16 @@ export const vModelText: ModelDirective< } el[assignKey](domValue) }) - if (trim) { + if (trim || castToNumber) { addEventListener(el, 'change', () => { - el.value = el.value.trim() + let newValue = el.value + if (trim) { + newValue = newValue.trim() + } + if (castToNumber) { + newValue = looseToNumber(newValue) + } + el.value = newValue }) } if (!lazy) { From ae42f08ca9d0839c9220e14a32754a28c0439cb2 Mon Sep 17 00:00:00 2001 From: Zhong Date: Thu, 2 Oct 2025 22:58:12 +0800 Subject: [PATCH 2/3] test: update --- packages/runtime-dom/__tests__/directives/vModel.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-dom/__tests__/directives/vModel.spec.ts b/packages/runtime-dom/__tests__/directives/vModel.spec.ts index 2e46eab6fc6..618bbdab938 100644 --- a/packages/runtime-dom/__tests__/directives/vModel.spec.ts +++ b/packages/runtime-dom/__tests__/directives/vModel.spec.ts @@ -344,8 +344,8 @@ describe('vModel', () => { triggerEvent('input', number) await nextTick() expect(data.number).toEqual(1.2) - await nextTick() triggerEvent('change', number) + await nextTick() expect(number.value).toEqual('1.2') trim.value = ' hello, world ' From 7c88b2e7695d18d729230ae99fe92891822021b3 Mon Sep 17 00:00:00 2001 From: daiwei Date: Tue, 14 Oct 2025 11:10:43 +0800 Subject: [PATCH 3/3] chore(v-model): refactor value casting logic into a separate function --- packages/runtime-dom/src/directives/vModel.ts | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index 448a9bd8e96..3b446e320c5 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -45,6 +45,12 @@ type ModelDirective = ObjectDirective< Modifiers > +function castValue(value: string, trim?: boolean, number?: boolean | null) { + if (trim) value = value.trim() + if (number) value = looseToNumber(value) + return value +} + // We are exporting the v-model runtime directly as vnode hooks so that it can // be tree-shaken in case v-model is never used. export const vModelText: ModelDirective< @@ -57,25 +63,11 @@ export const vModelText: ModelDirective< number || (vnode.props && vnode.props.type === 'number') addEventListener(el, lazy ? 'change' : 'input', e => { if ((e.target as any).composing) return - let domValue: string | number = el.value - if (trim) { - domValue = domValue.trim() - } - if (castToNumber) { - domValue = looseToNumber(domValue) - } - el[assignKey](domValue) + el[assignKey](castValue(el.value, trim, castToNumber)) }) if (trim || castToNumber) { addEventListener(el, 'change', () => { - let newValue = el.value - if (trim) { - newValue = newValue.trim() - } - if (castToNumber) { - newValue = looseToNumber(newValue) - } - el.value = newValue + el.value = castValue(el.value, trim, castToNumber) }) } if (!lazy) {