From fbb9d85493ceaaf520a326bd3a1d00bd2aaa2d41 Mon Sep 17 00:00:00 2001 From: Alex Liu Date: Mon, 19 Aug 2024 13:33:48 +0800 Subject: [PATCH 1/3] fix(runtime-dom): avoid unnecessary prop patch for checkbox --- packages/runtime-dom/src/modules/props.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/runtime-dom/src/modules/props.ts b/packages/runtime-dom/src/modules/props.ts index 7b7b700e048..46ea7c3ed1c 100644 --- a/packages/runtime-dom/src/modules/props.ts +++ b/packages/runtime-dom/src/modules/props.ts @@ -32,7 +32,14 @@ export function patchDOMProp( // compare against its attribute value instead. const oldValue = tag === 'OPTION' ? el.getAttribute('value') || '' : el.value - const newValue = value == null ? '' : String(value) + const newValue = + value == null + ? // #11647: value should be set as empty string for null and undefined, + // but should be set as 'no'. + el.type === 'checkbox' + ? 'on' + : '' + : String(value) if (oldValue !== newValue || !('_value' in el)) { el.value = newValue } From fac185bc170e62ee52f54470009dfd2d261ea246 Mon Sep 17 00:00:00 2001 From: Alex Liu Date: Mon, 19 Aug 2024 13:50:41 +0800 Subject: [PATCH 2/3] chore: fix typo --- packages/runtime-dom/src/modules/props.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-dom/src/modules/props.ts b/packages/runtime-dom/src/modules/props.ts index 46ea7c3ed1c..51d2e7fcc00 100644 --- a/packages/runtime-dom/src/modules/props.ts +++ b/packages/runtime-dom/src/modules/props.ts @@ -35,7 +35,7 @@ export function patchDOMProp( const newValue = value == null ? // #11647: value should be set as empty string for null and undefined, - // but should be set as 'no'. + // but should be set as 'on'. el.type === 'checkbox' ? 'on' : '' From 217dafc29988b65db08db5b5338f98654620ac51 Mon Sep 17 00:00:00 2001 From: Alex Liu Date: Mon, 19 Aug 2024 18:33:40 +0800 Subject: [PATCH 3/3] test: add test case --- .../runtime-dom/__tests__/patchProps.spec.ts | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/runtime-dom/__tests__/patchProps.spec.ts b/packages/runtime-dom/__tests__/patchProps.spec.ts index 952508f8f91..304d9f9c136 100644 --- a/packages/runtime-dom/__tests__/patchProps.spec.ts +++ b/packages/runtime-dom/__tests__/patchProps.spec.ts @@ -1,5 +1,12 @@ import { patchProp } from '../src/patchProp' -import { h, nextTick, ref, render } from '../src' +import { + h, + nextTick, + ref, + render, + vModelCheckbox, + withDirectives, +} from '../src' describe('runtime-dom: props patching', () => { test('basic', () => { @@ -351,4 +358,40 @@ describe('runtime-dom: props patching', () => { expect(el.translate).toBeFalsy() expect(el.getAttribute('translate')).toBe('no') }) + + // #11647 + test('should not trigger input mutation when `value` is `undefined`', async () => { + const fn = vi.fn() + const comp = { + setup() { + const checked = ref() + return () => + withDirectives( + h('input', { + type: 'checkbox', + value: undefined, + 'onUpdate:modelValue': (value: any) => { + checked.value = value + }, + }), + [[vModelCheckbox, checked.value]], + ) + }, + } + + const root = document.createElement('div') + render(h(comp), root) + document.body.append(root) + + const el = root.children[0] as HTMLInputElement + const observer = new MutationObserver(fn) + observer.observe(el, { + attributes: true, + }) + + el.click() + await nextTick() + + expect(fn).toBeCalledTimes(0) + }) })