From 40f4b77bb570868cb6e47791078767797e465989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E9=9B=BE=E4=B8=89=E8=AF=AD?= <32354856+baiwusanyu-c@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:14:38 +0800 Subject: [PATCH] fix(v-model): avoid overwriting number input with same value (#7004) close #7003 --- .../__tests__/directives/vModel.spec.ts | 55 +++++++++++++++++++ packages/runtime-dom/src/directives/vModel.ts | 23 ++++---- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/packages/runtime-dom/__tests__/directives/vModel.spec.ts b/packages/runtime-dom/__tests__/directives/vModel.spec.ts index 73b8f18afc0..acf1b40b696 100644 --- a/packages/runtime-dom/__tests__/directives/vModel.spec.ts +++ b/packages/runtime-dom/__tests__/directives/vModel.spec.ts @@ -101,6 +101,61 @@ describe('vModel', () => { expect(data.value).toEqual(1) }) + // #7003 + it('should work with number input and be able to update rendering correctly', async () => { + const setValue1 = function (this: any, value: any) { + this.value1 = value + } + const setValue2 = function (this: any, value: any) { + this.value2 = value + } + const component = defineComponent({ + data() { + return { value1: 1.002, value2: 1.002 } + }, + render() { + return [ + withVModel( + h('input', { + id: 'input_num1', + type: 'number', + 'onUpdate:modelValue': setValue1.bind(this) + }), + this.value1 + ), + withVModel( + h('input', { + id: 'input_num2', + type: 'number', + 'onUpdate:modelValue': setValue2.bind(this) + }), + this.value2 + ) + ] + } + }) + render(h(component), root) + const data = root._vnode.component.data + + const inputNum1 = root.querySelector('#input_num1')! + expect(inputNum1.value).toBe('1.002') + + const inputNum2 = root.querySelector('#input_num2')! + expect(inputNum2.value).toBe('1.002') + + inputNum1.value = '1.00' + triggerEvent('input', inputNum1) + await nextTick() + expect(data.value1).toBe(1) + + inputNum2.value = '1.00' + triggerEvent('input', inputNum2) + await nextTick() + expect(data.value2).toBe(1) + + expect(inputNum1.value).toBe('1.00') + }) + it('should work with multiple listeners', async () => { const spy = vi.fn() const component = defineComponent({ diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index 89cd5f9d49f..1bc4e76dfbc 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -83,24 +83,25 @@ export const vModelText: ModelDirective< el[assignKey] = getModelAssigner(vnode) // avoid clearing unresolved text. #2302 if ((el as any).composing) return + + const elValue = + number || el.type === 'number' ? looseToNumber(el.value) : el.value + const newValue = value == null ? '' : value + + if (elValue === newValue) { + return + } + if (document.activeElement === el && el.type !== 'range') { if (lazy) { return } - if (trim && el.value.trim() === value) { - return - } - if ( - (number || el.type === 'number') && - looseToNumber(el.value) === value - ) { + if (trim && el.value.trim() === newValue) { return } } - const newValue = value == null ? '' : value - if (el.value !== newValue) { - el.value = newValue - } + + el.value = newValue } }