From ea943afe404c4ca4b729906c5e8daf7aa2ccde9b Mon Sep 17 00:00:00 2001 From: Tycho Date: Fri, 11 Oct 2024 21:00:08 +0800 Subject: [PATCH] fix(runtime-dom): prevent unnecessary updates in v-model checkbox when value is unchanged (#12146) close #12144 --- packages/runtime-dom/src/directives/vModel.ts | 3 +- packages/vue/__tests__/e2e/vModel.spec.ts | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 packages/vue/__tests__/e2e/vModel.spec.ts diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index 5a27b245a66..5057e16d472 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -160,7 +160,7 @@ export const vModelCheckbox: ModelDirective = { function setChecked( el: HTMLInputElement, - { value }: DirectiveBinding, + { value, oldValue }: DirectiveBinding, vnode: VNode, ) { // store the v-model value on the element so it can be accessed by the @@ -173,6 +173,7 @@ function setChecked( } else if (isSet(value)) { checked = value.has(vnode.props!.value) } else { + if (value === oldValue) return checked = looseEqual(value, getCheckboxValue(el, true)) } diff --git a/packages/vue/__tests__/e2e/vModel.spec.ts b/packages/vue/__tests__/e2e/vModel.spec.ts new file mode 100644 index 00000000000..e1a06bda532 --- /dev/null +++ b/packages/vue/__tests__/e2e/vModel.spec.ts @@ -0,0 +1,57 @@ +import path from 'node:path' +import { setupPuppeteer } from './e2eUtils' + +const { page, click, isChecked } = setupPuppeteer() +import { nextTick } from 'vue' + +beforeEach(async () => { + await page().addScriptTag({ + path: path.resolve(__dirname, '../../dist/vue.global.js'), + }) + await page().setContent(`
`) +}) + +// #12144 +test('checkbox click with v-model', async () => { + await page().evaluate(() => { + const { createApp } = (window as any).Vue + createApp({ + template: ` + +
+ + `, + data() { + return { + first: true, + second: false, + } + }, + methods: { + secondClick(this: any) { + this.first = false + }, + }, + }).mount('#app') + }) + + expect(await isChecked('#first')).toBe(true) + expect(await isChecked('#second')).toBe(false) + await click('#second') + await nextTick() + expect(await isChecked('#first')).toBe(false) + expect(await isChecked('#second')).toBe(true) +})