From 8b7a035d1472fa5aa0bd27acdcba855dc2325c26 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 19 Mar 2025 17:59:02 +0800 Subject: [PATCH 1/6] fix: use modelValueModifiers intead of modelModifiers --- .../__tests__/transforms/vModel.spec.ts | 6 +++--- .../compiler-core/src/transforms/vModel.ts | 2 +- .../__snapshots__/defineModel.spec.ts.snap | 20 +++++++++---------- .../compileScript/defineModel.spec.ts | 2 +- .../compiler-sfc/src/script/defineModel.ts | 4 +--- .../__tests__/componentEmits.spec.ts | 10 +++++----- packages/runtime-core/src/helpers/useModel.ts | 10 +++++----- 7 files changed, 26 insertions(+), 28 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/vModel.spec.ts b/packages/compiler-core/__tests__/transforms/vModel.spec.ts index 82dd4909fd6..d092e72019e 100644 --- a/packages/compiler-core/__tests__/transforms/vModel.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vModel.spec.ts @@ -449,7 +449,7 @@ describe('compiler: transform v-model', () => { expect(codegen.dynamicProps).toBe(`["modelValue", "onUpdate:modelValue"]`) }) - test('should generate modelModifiers for component v-model', () => { + test('should generate modelValueModifiers for component v-model', () => { const root = parseWithVModel('', { prefixIdentifiers: true, }) @@ -461,7 +461,7 @@ describe('compiler: transform v-model', () => { { key: { content: `modelValue` } }, { key: { content: `onUpdate:modelValue` } }, { - key: { content: 'modelModifiers' }, + key: { content: 'modelValueModifiers' }, value: { content: `{ trim: true, "bar-baz": true }`, isStatic: false, @@ -469,7 +469,7 @@ describe('compiler: transform v-model', () => { }, ], }) - // should NOT include modelModifiers in dynamicPropNames because it's never + // should NOT include modelValueModifiers in dynamicPropNames because it's never // gonna change expect(vnodeCall.dynamicProps).toBe(`["modelValue", "onUpdate:modelValue"]`) }) diff --git a/packages/compiler-core/src/transforms/vModel.ts b/packages/compiler-core/src/transforms/vModel.ts index 598c1ea4387..c75ef1c3e60 100644 --- a/packages/compiler-core/src/transforms/vModel.ts +++ b/packages/compiler-core/src/transforms/vModel.ts @@ -138,7 +138,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => { ? isStaticExp(arg) ? `${arg.content}Modifiers` : createCompoundExpression([arg, ' + "Modifiers"']) - : `modelModifiers` + : `modelValueModifiers` props.push( createObjectProperty( modifiersKey, diff --git a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap index 12462dcf423..cdf71076819 100644 --- a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap @@ -6,7 +6,7 @@ exports[`defineModel() > basic usage 1`] = ` export default { props: { "modelValue": { required: true }, - "modelModifiers": {}, + "modelValueModifiers": {}, "count": {}, "countModifiers": {}, "toString": { type: Function }, @@ -34,7 +34,7 @@ export default /*@__PURE__*/_defineComponent({ "modelValue": { required: true }, - "modelModifiers": {}, + "modelValueModifiers": {}, }, emits: ["update:modelValue"], setup(__props, { expose: __expose }) { @@ -60,7 +60,7 @@ export default /*@__PURE__*/_defineComponent({ default: 0, required: true, }, - "modelModifiers": {}, + "modelValueModifiers": {}, }, emits: ["update:modelValue"], setup(__props, { expose: __expose }) { @@ -86,7 +86,7 @@ export default /*@__PURE__*/_defineComponent({ }, { "modelValue": { }, - "modelModifiers": {}, + "modelValueModifiers": {}, }), emits: ["update:modelValue"], setup(__props: any, { expose: __expose }) { @@ -109,7 +109,7 @@ exports[`defineModel() > w/ Boolean And Function types, production mode 1`] = ` export default /*@__PURE__*/_defineComponent({ props: { "modelValue": { type: [Boolean, String] }, - "modelModifiers": {}, + "modelValueModifiers": {}, }, emits: ["update:modelValue"], setup(__props, { expose: __expose }) { @@ -150,7 +150,7 @@ exports[`defineModel() > w/ defineProps and defineEmits 1`] = ` export default { props: /*@__PURE__*/_mergeModels({ foo: String }, { "modelValue": { default: 0 }, - "modelModifiers": {}, + "modelValueModifiers": {}, }), emits: /*@__PURE__*/_mergeModels(['change'], ["update:modelValue"]), setup(__props, { expose: __expose }) { @@ -172,7 +172,7 @@ exports[`defineModel() > w/ types, basic usage 1`] = ` export default /*@__PURE__*/_defineComponent({ props: { "modelValue": { type: [Boolean, String] }, - "modelModifiers": {}, + "modelValueModifiers": {}, "count": { type: Number }, "countModifiers": {}, "disabled": { type: Number, ...{ required: false } }, @@ -201,7 +201,7 @@ exports[`defineModel() > w/ types, production mode 1`] = ` export default /*@__PURE__*/_defineComponent({ props: { "modelValue": { type: Boolean }, - "modelModifiers": {}, + "modelValueModifiers": {}, "fn": {}, "fnModifiers": {}, "fnWithDefault": { type: Function, ...{ default: () => null } }, @@ -233,7 +233,7 @@ exports[`defineModel() > w/ types, production mode, boolean + multiple types 1`] export default /*@__PURE__*/_defineComponent({ props: { "modelValue": { type: [Boolean, String, Object] }, - "modelModifiers": {}, + "modelValueModifiers": {}, }, emits: ["update:modelValue"], setup(__props, { expose: __expose }) { @@ -253,7 +253,7 @@ exports[`defineModel() > w/ types, production mode, function + runtime opts + mu export default /*@__PURE__*/_defineComponent({ props: { "modelValue": { type: [Number, Function], ...{ default: () => 1 } }, - "modelModifiers": {}, + "modelValueModifiers": {}, }, emits: ["update:modelValue"], setup(__props, { expose: __expose }) { diff --git a/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts b/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts index 5d696a95d88..210c18ddaec 100644 --- a/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts @@ -94,7 +94,7 @@ describe('defineModel()', () => { ) assertCode(content) expect(content).toMatch('"modelValue": { type: [Boolean, String] }') - expect(content).toMatch('"modelModifiers": {}') + expect(content).toMatch('"modelValueModifiers": {}') expect(content).toMatch('"count": { type: Number }') expect(content).toMatch( '"disabled": { type: Number, ...{ required: false } }', diff --git a/packages/compiler-sfc/src/script/defineModel.ts b/packages/compiler-sfc/src/script/defineModel.ts index 05082800284..9c8f254fee4 100644 --- a/packages/compiler-sfc/src/script/defineModel.ts +++ b/packages/compiler-sfc/src/script/defineModel.ts @@ -167,9 +167,7 @@ export function genModelProps(ctx: ScriptCompileContext) { modelPropsDecl += `\n ${JSON.stringify(name)}: ${decl},` // also generate modifiers prop - const modifierPropName = JSON.stringify( - name === 'modelValue' ? `modelModifiers` : `${name}Modifiers`, - ) + const modifierPropName = JSON.stringify(`${name}Modifiers`) modelPropsDecl += `\n ${modifierPropName}: {},` } return `{${modelPropsDecl}\n }` diff --git a/packages/runtime-core/__tests__/componentEmits.spec.ts b/packages/runtime-core/__tests__/componentEmits.spec.ts index dc82c04919f..c793433921a 100644 --- a/packages/runtime-core/__tests__/componentEmits.spec.ts +++ b/packages/runtime-core/__tests__/componentEmits.spec.ts @@ -325,7 +325,7 @@ describe('component: emit', () => { const Comp = () => h(Foo, { modelValue: null, - modelModifiers: { number: true }, + modelValueModifiers: { number: true }, 'onUpdate:modelValue': fn1, foo: null, @@ -356,7 +356,7 @@ describe('component: emit', () => { const Comp = () => h(Foo, { modelValue: null, - modelModifiers: { trim: true }, + modelValueModifiers: { trim: true }, 'onUpdate:modelValue': fn1, foo: null, @@ -410,7 +410,7 @@ describe('component: emit', () => { const Comp = () => h(Foo, { modelValue: null, - modelModifiers: { trim: true }, + modelValueModifiers: { trim: true }, 'onUpdate:modelValue': fn1, firstName: null, @@ -464,7 +464,7 @@ describe('component: emit', () => { const Comp = () => h(Foo, { modelValue: null, - modelModifiers: { trim: true, number: true }, + modelValueModifiers: { trim: true, number: true }, 'onUpdate:modelValue': fn1, foo: null, @@ -492,7 +492,7 @@ describe('component: emit', () => { const Comp = () => h(Foo, { modelValue: null, - modelModifiers: { trim: true }, + modelValueModifiers: { trim: true }, 'onUpdate:modelValue': fn, }) diff --git a/packages/runtime-core/src/helpers/useModel.ts b/packages/runtime-core/src/helpers/useModel.ts index e85edc6e9a7..603a7bf6ea8 100644 --- a/packages/runtime-core/src/helpers/useModel.ts +++ b/packages/runtime-core/src/helpers/useModel.ts @@ -145,9 +145,9 @@ export const getModelModifiers = ( modelName: string, getter: (props: Record, key: string) => any, ): Record | undefined => { - return modelName === 'modelValue' || modelName === 'model-value' - ? getter(props, 'modelModifiers') - : getter(props, `${modelName}Modifiers`) || - getter(props, `${camelize(modelName)}Modifiers`) || - getter(props, `${hyphenate(modelName)}Modifiers`) + return ( + getter(props, `${modelName}Modifiers`) || + getter(props, `${camelize(modelName)}Modifiers`) || + getter(props, `${hyphenate(modelName)}Modifiers`) + ) } From 9df9281b506451667e0d5cc5e67420028a091224 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 20 Mar 2025 10:35:30 +0800 Subject: [PATCH 2/6] feat: use for vapor --- .../transforms/__snapshots__/vModel.spec.ts.snap | 4 ++-- .../compiler-vapor/__tests__/transforms/vModel.spec.ts | 4 ++-- packages/compiler-vapor/src/generators/component.ts | 4 +--- packages/runtime-vapor/__tests__/componentEmits.spec.ts | 8 ++++---- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap index 5ef064974c0..14330e57811 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap @@ -1,13 +1,13 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`compiler: vModel transform > component > v-model for component should generate modelModifiers 1`] = ` +exports[`compiler: vModel transform > component > v-model for component should generate modelValueModifiers 1`] = ` "import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue'; export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") const n0 = _createComponentWithFallback(_component_Comp, { modelValue: () => (_ctx.foo), "onUpdate:modelValue": () => _value => (_ctx.foo = _value), - modelModifiers: () => ({ trim: true, "bar-baz": true }) }, null, true) + modelValueModifiers: () => ({ trim: true, "bar-baz": true }) }, null, true) return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts index 51eaa9e0230..bed60ff63a5 100644 --- a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts @@ -266,13 +266,13 @@ describe('compiler: vModel transform', () => { }) }) - test('v-model for component should generate modelModifiers', () => { + test('v-model for component should generate modelValueModifiers', () => { const { code, ir } = compileWithVModel( '', ) expect(code).toMatchSnapshot() expect(code).contain( - `modelModifiers: () => ({ trim: true, "bar-baz": true })`, + `modelValueModifiers: () => ({ trim: true, "bar-baz": true })`, ) expect(ir.block.dynamic.children[0].operation).toMatchObject({ type: IRNodeTypes.CREATE_COMPONENT_NODE, diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index 7c232db754b..1c251928ce5 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -240,9 +240,7 @@ function genModelModifiers( if (!modelModifiers || !modelModifiers.length) return [] const modifiersKey = key.isStatic - ? key.content === 'modelValue' - ? [`modelModifiers`] - : [`${key.content}Modifiers`] + ? [`${key.content}Modifiers`] : ['[', ...genExpression(key, context), ' + "Modifiers"]'] const modifiersVal = genDirectiveModifiers(modelModifiers) diff --git a/packages/runtime-vapor/__tests__/componentEmits.spec.ts b/packages/runtime-vapor/__tests__/componentEmits.spec.ts index 8c8a56085ba..6b542bbf6cc 100644 --- a/packages/runtime-vapor/__tests__/componentEmits.spec.ts +++ b/packages/runtime-vapor/__tests__/componentEmits.spec.ts @@ -265,7 +265,7 @@ describe('component: emit', () => { const fn2 = vi.fn() render({ modelValue: () => null, - modelModifiers: () => ({ number: true }), + modelValueModifiers: () => ({ number: true }), ['onUpdate:modelValue']: () => fn1, foo: () => null, fooModifiers: () => ({ number: true }), @@ -291,7 +291,7 @@ describe('component: emit', () => { modelValue() { return null }, - modelModifiers() { + modelValueModifiers() { return { trim: true } }, ['onUpdate:modelValue']() { @@ -327,7 +327,7 @@ describe('component: emit', () => { modelValue() { return null }, - modelModifiers() { + modelValueModifiers() { return { trim: true, number: true } }, ['onUpdate:modelValue']() { @@ -361,7 +361,7 @@ describe('component: emit', () => { modelValue() { return null }, - modelModifiers() { + modelValueModifiers() { return { trim: true } }, ['onUpdate:modelValue']() { From c4e45ff87bda07d7b59c54fc8fa97817dad8c817 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 3 Jul 2025 22:01:41 +0800 Subject: [PATCH 3/6] chore: use model$ --- .../__tests__/transforms/vModel.spec.ts | 24 +++++++++++-- .../compiler-core/src/transforms/vModel.ts | 4 +-- .../__snapshots__/defineModel.spec.ts.snap | 20 +++++------ .../compileScript/defineModel.spec.ts | 2 +- .../__tests__/compileStyle.spec.ts | 36 ++++++++++--------- .../compiler-sfc/src/script/defineModel.ts | 6 +++- .../__snapshots__/vModel.spec.ts.snap | 16 +++++++-- .../__tests__/transforms/vModel.spec.ts | 26 ++++++++++++-- .../src/generators/component.ts | 6 +++- .../__tests__/componentEmits.spec.ts | 10 +++--- packages/runtime-core/src/helpers/useModel.ts | 13 ++++--- .../__tests__/componentEmits.spec.ts | 8 ++--- 12 files changed, 119 insertions(+), 52 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/vModel.spec.ts b/packages/compiler-core/__tests__/transforms/vModel.spec.ts index d092e72019e..bf69583c3d6 100644 --- a/packages/compiler-core/__tests__/transforms/vModel.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vModel.spec.ts @@ -449,7 +449,7 @@ describe('compiler: transform v-model', () => { expect(codegen.dynamicProps).toBe(`["modelValue", "onUpdate:modelValue"]`) }) - test('should generate modelValueModifiers for component v-model', () => { + test('should generate modelModifiers for component v-model', () => { const root = parseWithVModel('', { prefixIdentifiers: true, }) @@ -461,7 +461,7 @@ describe('compiler: transform v-model', () => { { key: { content: `modelValue` } }, { key: { content: `onUpdate:modelValue` } }, { - key: { content: 'modelValueModifiers' }, + key: { content: 'modelModifiers' }, value: { content: `{ trim: true, "bar-baz": true }`, isStatic: false, @@ -469,7 +469,7 @@ describe('compiler: transform v-model', () => { }, ], }) - // should NOT include modelValueModifiers in dynamicPropNames because it's never + // should NOT include modelModifiers in dynamicPropNames because it's never // gonna change expect(vnodeCall.dynamicProps).toBe(`["modelValue", "onUpdate:modelValue"]`) }) @@ -507,6 +507,24 @@ describe('compiler: transform v-model', () => { ) }) + test('should generate model$Modifiers for component v-model:model with arguments', () => { + const root = parseWithVModel('', { + prefixIdentifiers: true, + }) + const vnodeCall = (root.children[0] as ComponentNode) + .codegenNode as VNodeCall + expect(vnodeCall.props).toMatchObject({ + properties: [ + { key: { content: `model` } }, + { key: { content: `onUpdate:model` } }, + { + key: { content: 'model$Modifiers' }, + value: { content: `{ trim: true }`, isStatic: false }, + }, + ], + }) + }) + describe('errors', () => { test('missing expression', () => { const onError = vi.fn() diff --git a/packages/compiler-core/src/transforms/vModel.ts b/packages/compiler-core/src/transforms/vModel.ts index c75ef1c3e60..0819ecdbfdb 100644 --- a/packages/compiler-core/src/transforms/vModel.ts +++ b/packages/compiler-core/src/transforms/vModel.ts @@ -136,9 +136,9 @@ export const transformModel: DirectiveTransform = (dir, node, context) => { .join(`, `) const modifiersKey = arg ? isStaticExp(arg) - ? `${arg.content}Modifiers` + ? `${arg.content}${arg.content === 'model' ? '$' : ''}Modifiers` : createCompoundExpression([arg, ' + "Modifiers"']) - : `modelValueModifiers` + : `modelModifiers` props.push( createObjectProperty( modifiersKey, diff --git a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap index cdf71076819..12462dcf423 100644 --- a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap @@ -6,7 +6,7 @@ exports[`defineModel() > basic usage 1`] = ` export default { props: { "modelValue": { required: true }, - "modelValueModifiers": {}, + "modelModifiers": {}, "count": {}, "countModifiers": {}, "toString": { type: Function }, @@ -34,7 +34,7 @@ export default /*@__PURE__*/_defineComponent({ "modelValue": { required: true }, - "modelValueModifiers": {}, + "modelModifiers": {}, }, emits: ["update:modelValue"], setup(__props, { expose: __expose }) { @@ -60,7 +60,7 @@ export default /*@__PURE__*/_defineComponent({ default: 0, required: true, }, - "modelValueModifiers": {}, + "modelModifiers": {}, }, emits: ["update:modelValue"], setup(__props, { expose: __expose }) { @@ -86,7 +86,7 @@ export default /*@__PURE__*/_defineComponent({ }, { "modelValue": { }, - "modelValueModifiers": {}, + "modelModifiers": {}, }), emits: ["update:modelValue"], setup(__props: any, { expose: __expose }) { @@ -109,7 +109,7 @@ exports[`defineModel() > w/ Boolean And Function types, production mode 1`] = ` export default /*@__PURE__*/_defineComponent({ props: { "modelValue": { type: [Boolean, String] }, - "modelValueModifiers": {}, + "modelModifiers": {}, }, emits: ["update:modelValue"], setup(__props, { expose: __expose }) { @@ -150,7 +150,7 @@ exports[`defineModel() > w/ defineProps and defineEmits 1`] = ` export default { props: /*@__PURE__*/_mergeModels({ foo: String }, { "modelValue": { default: 0 }, - "modelValueModifiers": {}, + "modelModifiers": {}, }), emits: /*@__PURE__*/_mergeModels(['change'], ["update:modelValue"]), setup(__props, { expose: __expose }) { @@ -172,7 +172,7 @@ exports[`defineModel() > w/ types, basic usage 1`] = ` export default /*@__PURE__*/_defineComponent({ props: { "modelValue": { type: [Boolean, String] }, - "modelValueModifiers": {}, + "modelModifiers": {}, "count": { type: Number }, "countModifiers": {}, "disabled": { type: Number, ...{ required: false } }, @@ -201,7 +201,7 @@ exports[`defineModel() > w/ types, production mode 1`] = ` export default /*@__PURE__*/_defineComponent({ props: { "modelValue": { type: Boolean }, - "modelValueModifiers": {}, + "modelModifiers": {}, "fn": {}, "fnModifiers": {}, "fnWithDefault": { type: Function, ...{ default: () => null } }, @@ -233,7 +233,7 @@ exports[`defineModel() > w/ types, production mode, boolean + multiple types 1`] export default /*@__PURE__*/_defineComponent({ props: { "modelValue": { type: [Boolean, String, Object] }, - "modelValueModifiers": {}, + "modelModifiers": {}, }, emits: ["update:modelValue"], setup(__props, { expose: __expose }) { @@ -253,7 +253,7 @@ exports[`defineModel() > w/ types, production mode, function + runtime opts + mu export default /*@__PURE__*/_defineComponent({ props: { "modelValue": { type: [Number, Function], ...{ default: () => 1 } }, - "modelValueModifiers": {}, + "modelModifiers": {}, }, emits: ["update:modelValue"], setup(__props, { expose: __expose }) { diff --git a/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts b/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts index 210c18ddaec..5d696a95d88 100644 --- a/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts @@ -94,7 +94,7 @@ describe('defineModel()', () => { ) assertCode(content) expect(content).toMatch('"modelValue": { type: [Boolean, String] }') - expect(content).toMatch('"modelValueModifiers": {}') + expect(content).toMatch('"modelModifiers": {}') expect(content).toMatch('"count": { type: Number }') expect(content).toMatch( '"disabled": { type: Number, ...{ required: false } }', diff --git a/packages/compiler-sfc/__tests__/compileStyle.spec.ts b/packages/compiler-sfc/__tests__/compileStyle.spec.ts index b76414364dc..78fd52425e8 100644 --- a/packages/compiler-sfc/__tests__/compileStyle.spec.ts +++ b/packages/compiler-sfc/__tests__/compileStyle.spec.ts @@ -211,38 +211,42 @@ color: red expect( compileScoped(`.div { color: red; } .div:where(:hover) { color: blue; }`), ).toMatchInlineSnapshot(` - ".div[data-v-test] { color: red; - } - .div[data-v-test]:where(:hover) { color: blue; - }"`) + ".div[data-v-test] { color: red; + } + .div[data-v-test]:where(:hover) { color: blue; + }" + `) expect( compileScoped(`.div { color: red; } .div:is(:hover) { color: blue; }`), ).toMatchInlineSnapshot(` - ".div[data-v-test] { color: red; - } - .div[data-v-test]:is(:hover) { color: blue; - }"`) + ".div[data-v-test] { color: red; + } + .div[data-v-test]:is(:hover) { color: blue; + }" + `) expect( compileScoped( `.div { color: red; } .div:where(.foo:hover) { color: blue; }`, ), ).toMatchInlineSnapshot(` - ".div[data-v-test] { color: red; - } - .div[data-v-test]:where(.foo:hover) { color: blue; - }"`) + ".div[data-v-test] { color: red; + } + .div[data-v-test]:where(.foo:hover) { color: blue; + }" + `) expect( compileScoped( `.div { color: red; } .div:is(.foo:hover) { color: blue; }`, ), ).toMatchInlineSnapshot(` - ".div[data-v-test] { color: red; - } - .div[data-v-test]:is(.foo:hover) { color: blue; - }"`) + ".div[data-v-test] { color: red; + } + .div[data-v-test]:is(.foo:hover) { color: blue; + }" + `) }) test('media query', () => { diff --git a/packages/compiler-sfc/src/script/defineModel.ts b/packages/compiler-sfc/src/script/defineModel.ts index 9c8f254fee4..43897819492 100644 --- a/packages/compiler-sfc/src/script/defineModel.ts +++ b/packages/compiler-sfc/src/script/defineModel.ts @@ -167,7 +167,11 @@ export function genModelProps(ctx: ScriptCompileContext) { modelPropsDecl += `\n ${JSON.stringify(name)}: ${decl},` // also generate modifiers prop - const modifierPropName = JSON.stringify(`${name}Modifiers`) + const modifierPropName = JSON.stringify( + name === 'modelValue' + ? `modelModifiers` + : `${name}${name === 'model' ? '$' : ''}Modifiers`, + ) modelPropsDecl += `\n ${modifierPropName}: {},` } return `{${modelPropsDecl}\n }` diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap index 14330e57811..b32c2fbf3f0 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap @@ -1,13 +1,13 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`compiler: vModel transform > component > v-model for component should generate modelValueModifiers 1`] = ` +exports[`compiler: vModel transform > component > v-model for component should generate modelModifiers 1`] = ` "import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue'; export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") const n0 = _createComponentWithFallback(_component_Comp, { modelValue: () => (_ctx.foo), "onUpdate:modelValue": () => _value => (_ctx.foo = _value), - modelValueModifiers: () => ({ trim: true, "bar-baz": true }) }, null, true) + modelModifiers: () => ({ trim: true, "bar-baz": true }) }, null, true) return n0 }" `; @@ -81,6 +81,18 @@ export function render(_ctx) { }" `; +exports[`compiler: vModel transform > component > v-model:model with arguments for component should generate model$Modifiers 1`] = ` +"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue'; + +export function render(_ctx) { + const _component_Comp = _resolveComponent("Comp") + const n0 = _createComponentWithFallback(_component_Comp, { model: () => (_ctx.foo), + "onUpdate:model": () => _value => (_ctx.foo = _value), + model$Modifiers: () => ({ trim: true }) }, null, true) + return n0 +}" +`; + exports[`compiler: vModel transform > modifiers > .lazy 1`] = ` "import { applyTextModel as _applyTextModel, template as _template } from 'vue'; const t0 = _template("", true) diff --git a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts index bed60ff63a5..8768f21ce53 100644 --- a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts @@ -266,13 +266,13 @@ describe('compiler: vModel transform', () => { }) }) - test('v-model for component should generate modelValueModifiers', () => { + test('v-model for component should generate modelModifiers', () => { const { code, ir } = compileWithVModel( '', ) expect(code).toMatchSnapshot() expect(code).contain( - `modelValueModifiers: () => ({ trim: true, "bar-baz": true })`, + `modelModifiers: () => ({ trim: true, "bar-baz": true })`, ) expect(ir.block.dynamic.children[0].operation).toMatchObject({ type: IRNodeTypes.CREATE_COMPONENT_NODE, @@ -319,6 +319,28 @@ describe('compiler: vModel transform', () => { }) }) + test('v-model:model with arguments for component should generate model$Modifiers', () => { + const { code, ir } = compileWithVModel( + '', + ) + expect(code).toMatchSnapshot() + expect(code).contain(`model$Modifiers: () => ({ trim: true })`) + expect(ir.block.dynamic.children[0].operation).toMatchObject({ + type: IRNodeTypes.CREATE_COMPONENT_NODE, + tag: 'Comp', + props: [ + [ + { + key: { content: 'model', isStatic: true }, + values: [{ content: 'foo', isStatic: false }], + model: true, + modelModifiers: ['trim'], + }, + ], + ], + }) + }) + test('v-model with dynamic arguments for component should generate modelModifiers ', () => { const { code, ir } = compileWithVModel( '', diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index 1c251928ce5..d993199ef0d 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -240,7 +240,11 @@ function genModelModifiers( if (!modelModifiers || !modelModifiers.length) return [] const modifiersKey = key.isStatic - ? [`${key.content}Modifiers`] + ? [ + key.content === 'modelValue' + ? `modelModifiers` + : `${key.content}${key.content === 'model' ? '$' : ''}Modifiers`, + ] : ['[', ...genExpression(key, context), ' + "Modifiers"]'] const modifiersVal = genDirectiveModifiers(modelModifiers) diff --git a/packages/runtime-core/__tests__/componentEmits.spec.ts b/packages/runtime-core/__tests__/componentEmits.spec.ts index c793433921a..dc82c04919f 100644 --- a/packages/runtime-core/__tests__/componentEmits.spec.ts +++ b/packages/runtime-core/__tests__/componentEmits.spec.ts @@ -325,7 +325,7 @@ describe('component: emit', () => { const Comp = () => h(Foo, { modelValue: null, - modelValueModifiers: { number: true }, + modelModifiers: { number: true }, 'onUpdate:modelValue': fn1, foo: null, @@ -356,7 +356,7 @@ describe('component: emit', () => { const Comp = () => h(Foo, { modelValue: null, - modelValueModifiers: { trim: true }, + modelModifiers: { trim: true }, 'onUpdate:modelValue': fn1, foo: null, @@ -410,7 +410,7 @@ describe('component: emit', () => { const Comp = () => h(Foo, { modelValue: null, - modelValueModifiers: { trim: true }, + modelModifiers: { trim: true }, 'onUpdate:modelValue': fn1, firstName: null, @@ -464,7 +464,7 @@ describe('component: emit', () => { const Comp = () => h(Foo, { modelValue: null, - modelValueModifiers: { trim: true, number: true }, + modelModifiers: { trim: true, number: true }, 'onUpdate:modelValue': fn1, foo: null, @@ -492,7 +492,7 @@ describe('component: emit', () => { const Comp = () => h(Foo, { modelValue: null, - modelValueModifiers: { trim: true }, + modelModifiers: { trim: true }, 'onUpdate:modelValue': fn, }) diff --git a/packages/runtime-core/src/helpers/useModel.ts b/packages/runtime-core/src/helpers/useModel.ts index 603a7bf6ea8..8023cfd445e 100644 --- a/packages/runtime-core/src/helpers/useModel.ts +++ b/packages/runtime-core/src/helpers/useModel.ts @@ -145,9 +145,12 @@ export const getModelModifiers = ( modelName: string, getter: (props: Record, key: string) => any, ): Record | undefined => { - return ( - getter(props, `${modelName}Modifiers`) || - getter(props, `${camelize(modelName)}Modifiers`) || - getter(props, `${hyphenate(modelName)}Modifiers`) - ) + return modelName === 'modelValue' || modelName === 'model-value' + ? getter(props, 'modelModifiers') + : getter( + props, + `${modelName}${modelName === 'model' ? '$' : ''}Modifiers`, + ) || + getter(props, `${camelize(modelName)}Modifiers`) || + getter(props, `${hyphenate(modelName)}Modifiers`) } diff --git a/packages/runtime-vapor/__tests__/componentEmits.spec.ts b/packages/runtime-vapor/__tests__/componentEmits.spec.ts index 6b542bbf6cc..8c8a56085ba 100644 --- a/packages/runtime-vapor/__tests__/componentEmits.spec.ts +++ b/packages/runtime-vapor/__tests__/componentEmits.spec.ts @@ -265,7 +265,7 @@ describe('component: emit', () => { const fn2 = vi.fn() render({ modelValue: () => null, - modelValueModifiers: () => ({ number: true }), + modelModifiers: () => ({ number: true }), ['onUpdate:modelValue']: () => fn1, foo: () => null, fooModifiers: () => ({ number: true }), @@ -291,7 +291,7 @@ describe('component: emit', () => { modelValue() { return null }, - modelValueModifiers() { + modelModifiers() { return { trim: true } }, ['onUpdate:modelValue']() { @@ -327,7 +327,7 @@ describe('component: emit', () => { modelValue() { return null }, - modelValueModifiers() { + modelModifiers() { return { trim: true, number: true } }, ['onUpdate:modelValue']() { @@ -361,7 +361,7 @@ describe('component: emit', () => { modelValue() { return null }, - modelValueModifiers() { + modelModifiers() { return { trim: true } }, ['onUpdate:modelValue']() { From d22026aeaf8563d78d710b9a657f824095cc9890 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 3 Jul 2025 22:08:08 +0800 Subject: [PATCH 4/6] chore: update --- .../__tests__/compileStyle.spec.ts | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/packages/compiler-sfc/__tests__/compileStyle.spec.ts b/packages/compiler-sfc/__tests__/compileStyle.spec.ts index 78fd52425e8..b76414364dc 100644 --- a/packages/compiler-sfc/__tests__/compileStyle.spec.ts +++ b/packages/compiler-sfc/__tests__/compileStyle.spec.ts @@ -211,42 +211,38 @@ color: red expect( compileScoped(`.div { color: red; } .div:where(:hover) { color: blue; }`), ).toMatchInlineSnapshot(` - ".div[data-v-test] { color: red; - } - .div[data-v-test]:where(:hover) { color: blue; - }" - `) + ".div[data-v-test] { color: red; + } + .div[data-v-test]:where(:hover) { color: blue; + }"`) expect( compileScoped(`.div { color: red; } .div:is(:hover) { color: blue; }`), ).toMatchInlineSnapshot(` - ".div[data-v-test] { color: red; - } - .div[data-v-test]:is(:hover) { color: blue; - }" - `) + ".div[data-v-test] { color: red; + } + .div[data-v-test]:is(:hover) { color: blue; + }"`) expect( compileScoped( `.div { color: red; } .div:where(.foo:hover) { color: blue; }`, ), ).toMatchInlineSnapshot(` - ".div[data-v-test] { color: red; - } - .div[data-v-test]:where(.foo:hover) { color: blue; - }" - `) + ".div[data-v-test] { color: red; + } + .div[data-v-test]:where(.foo:hover) { color: blue; + }"`) expect( compileScoped( `.div { color: red; } .div:is(.foo:hover) { color: blue; }`, ), ).toMatchInlineSnapshot(` - ".div[data-v-test] { color: red; - } - .div[data-v-test]:is(.foo:hover) { color: blue; - }" - `) + ".div[data-v-test] { color: red; + } + .div[data-v-test]:is(.foo:hover) { color: blue; + }"`) }) test('media query', () => { From 2029be57c1d898474b13aa81395666e766a24731 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 3 Jul 2025 23:26:34 +0800 Subject: [PATCH 5/6] chore: update --- packages/compiler-core/__tests__/transforms/vModel.spec.ts | 4 ++-- packages/compiler-core/src/transforms/vModel.ts | 2 +- packages/compiler-sfc/src/script/defineModel.ts | 2 +- .../__tests__/transforms/__snapshots__/vModel.spec.ts.snap | 4 ++-- packages/compiler-vapor/__tests__/transforms/vModel.spec.ts | 4 ++-- packages/compiler-vapor/src/generators/component.ts | 2 +- packages/runtime-core/src/helpers/useModel.ts | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/vModel.spec.ts b/packages/compiler-core/__tests__/transforms/vModel.spec.ts index bf69583c3d6..10a1952988a 100644 --- a/packages/compiler-core/__tests__/transforms/vModel.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vModel.spec.ts @@ -507,7 +507,7 @@ describe('compiler: transform v-model', () => { ) }) - test('should generate model$Modifiers for component v-model:model with arguments', () => { + test('should generate modelModifiers$ for component v-model:model with arguments', () => { const root = parseWithVModel('', { prefixIdentifiers: true, }) @@ -518,7 +518,7 @@ describe('compiler: transform v-model', () => { { key: { content: `model` } }, { key: { content: `onUpdate:model` } }, { - key: { content: 'model$Modifiers' }, + key: { content: 'modelModifiers$' }, value: { content: `{ trim: true }`, isStatic: false }, }, ], diff --git a/packages/compiler-core/src/transforms/vModel.ts b/packages/compiler-core/src/transforms/vModel.ts index 0819ecdbfdb..dcb2a6f6c25 100644 --- a/packages/compiler-core/src/transforms/vModel.ts +++ b/packages/compiler-core/src/transforms/vModel.ts @@ -136,7 +136,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => { .join(`, `) const modifiersKey = arg ? isStaticExp(arg) - ? `${arg.content}${arg.content === 'model' ? '$' : ''}Modifiers` + ? `${arg.content}Modifiers${arg.content === 'model' ? '$' : ''}` : createCompoundExpression([arg, ' + "Modifiers"']) : `modelModifiers` props.push( diff --git a/packages/compiler-sfc/src/script/defineModel.ts b/packages/compiler-sfc/src/script/defineModel.ts index 43897819492..29479f13dcd 100644 --- a/packages/compiler-sfc/src/script/defineModel.ts +++ b/packages/compiler-sfc/src/script/defineModel.ts @@ -170,7 +170,7 @@ export function genModelProps(ctx: ScriptCompileContext) { const modifierPropName = JSON.stringify( name === 'modelValue' ? `modelModifiers` - : `${name}${name === 'model' ? '$' : ''}Modifiers`, + : `${name}Modifiers${name === 'model' ? '$' : ''}`, ) modelPropsDecl += `\n ${modifierPropName}: {},` } diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap index b32c2fbf3f0..77a689796af 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap @@ -81,14 +81,14 @@ export function render(_ctx) { }" `; -exports[`compiler: vModel transform > component > v-model:model with arguments for component should generate model$Modifiers 1`] = ` +exports[`compiler: vModel transform > component > v-model:model with arguments for component should generate modelModifiers$ 1`] = ` "import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue'; export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") const n0 = _createComponentWithFallback(_component_Comp, { model: () => (_ctx.foo), "onUpdate:model": () => _value => (_ctx.foo = _value), - model$Modifiers: () => ({ trim: true }) }, null, true) + modelModifiers$: () => ({ trim: true }) }, null, true) return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts index 8768f21ce53..23b99ec7019 100644 --- a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts @@ -319,12 +319,12 @@ describe('compiler: vModel transform', () => { }) }) - test('v-model:model with arguments for component should generate model$Modifiers', () => { + test('v-model:model with arguments for component should generate modelModifiers$', () => { const { code, ir } = compileWithVModel( '', ) expect(code).toMatchSnapshot() - expect(code).contain(`model$Modifiers: () => ({ trim: true })`) + expect(code).contain(`modelModifiers$: () => ({ trim: true })`) expect(ir.block.dynamic.children[0].operation).toMatchObject({ type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index d993199ef0d..d2ac1436d3b 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -243,7 +243,7 @@ function genModelModifiers( ? [ key.content === 'modelValue' ? `modelModifiers` - : `${key.content}${key.content === 'model' ? '$' : ''}Modifiers`, + : `${key.content}Modifiers${key.content === 'model' ? '$' : ''}`, ] : ['[', ...genExpression(key, context), ' + "Modifiers"]'] diff --git a/packages/runtime-core/src/helpers/useModel.ts b/packages/runtime-core/src/helpers/useModel.ts index 8023cfd445e..d32a122c6de 100644 --- a/packages/runtime-core/src/helpers/useModel.ts +++ b/packages/runtime-core/src/helpers/useModel.ts @@ -149,7 +149,7 @@ export const getModelModifiers = ( ? getter(props, 'modelModifiers') : getter( props, - `${modelName}${modelName === 'model' ? '$' : ''}Modifiers`, + `${modelName}Modifiers${modelName === 'model' ? '$' : ''}`, ) || getter(props, `${camelize(modelName)}Modifiers`) || getter(props, `${hyphenate(modelName)}Modifiers`) From f3b3cbd6bd64c49b3227a3ada3ae237a05e7d055 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 4 Jul 2025 00:50:33 +0800 Subject: [PATCH 6/6] chore: add getModifierPropName --- .../compiler-core/src/transforms/vModel.ts | 4 ++-- .../compiler-sfc/src/script/defineModel.ts | 7 ++----- .../src/generators/component.ts | 8 ++----- packages/runtime-core/src/helpers/useModel.ts | 21 +++++++++++-------- packages/shared/src/general.ts | 12 +++++++++++ 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/packages/compiler-core/src/transforms/vModel.ts b/packages/compiler-core/src/transforms/vModel.ts index dcb2a6f6c25..40e6a86f10f 100644 --- a/packages/compiler-core/src/transforms/vModel.ts +++ b/packages/compiler-core/src/transforms/vModel.ts @@ -18,7 +18,7 @@ import { } from '../utils' import { IS_REF } from '../runtimeHelpers' import { BindingTypes } from '../options' -import { camelize } from '@vue/shared' +import { camelize, getModifierPropName } from '@vue/shared' export const transformModel: DirectiveTransform = (dir, node, context) => { const { exp, arg } = dir @@ -136,7 +136,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => { .join(`, `) const modifiersKey = arg ? isStaticExp(arg) - ? `${arg.content}Modifiers${arg.content === 'model' ? '$' : ''}` + ? getModifierPropName(arg.content) : createCompoundExpression([arg, ' + "Modifiers"']) : `modelModifiers` props.push( diff --git a/packages/compiler-sfc/src/script/defineModel.ts b/packages/compiler-sfc/src/script/defineModel.ts index 29479f13dcd..75c8e2cdb79 100644 --- a/packages/compiler-sfc/src/script/defineModel.ts +++ b/packages/compiler-sfc/src/script/defineModel.ts @@ -3,6 +3,7 @@ import type { ScriptCompileContext } from './context' import { inferRuntimeType } from './resolveType' import { UNKNOWN_TYPE, isCallOf, toRuntimeTypeString } from './utils' import { BindingTypes, unwrapTSNode } from '@vue/compiler-dom' +import { getModifierPropName } from '@vue/shared' export const DEFINE_MODEL = 'defineModel' @@ -167,11 +168,7 @@ export function genModelProps(ctx: ScriptCompileContext) { modelPropsDecl += `\n ${JSON.stringify(name)}: ${decl},` // also generate modifiers prop - const modifierPropName = JSON.stringify( - name === 'modelValue' - ? `modelModifiers` - : `${name}Modifiers${name === 'model' ? '$' : ''}`, - ) + const modifierPropName = JSON.stringify(getModifierPropName(name)) modelPropsDecl += `\n ${modifierPropName}: {},` } return `{${modelPropsDecl}\n }` diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index d2ac1436d3b..516bf94b048 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -1,4 +1,4 @@ -import { camelize, extend, isArray } from '@vue/shared' +import { camelize, extend, getModifierPropName, isArray } from '@vue/shared' import type { CodegenContext } from '../generate' import { type CreateComponentIRNode, @@ -240,11 +240,7 @@ function genModelModifiers( if (!modelModifiers || !modelModifiers.length) return [] const modifiersKey = key.isStatic - ? [ - key.content === 'modelValue' - ? `modelModifiers` - : `${key.content}Modifiers${key.content === 'model' ? '$' : ''}`, - ] + ? [getModifierPropName(key.content)] : ['[', ...genExpression(key, context), ' + "Modifiers"]'] const modifiersVal = genDirectiveModifiers(modelModifiers) diff --git a/packages/runtime-core/src/helpers/useModel.ts b/packages/runtime-core/src/helpers/useModel.ts index d32a122c6de..f2a8be36a54 100644 --- a/packages/runtime-core/src/helpers/useModel.ts +++ b/packages/runtime-core/src/helpers/useModel.ts @@ -1,5 +1,11 @@ import { type Ref, customRef, ref } from '@vue/reactivity' -import { EMPTY_OBJ, camelize, hasChanged, hyphenate } from '@vue/shared' +import { + EMPTY_OBJ, + camelize, + getModifierPropName, + hasChanged, + hyphenate, +} from '@vue/shared' import type { DefineModelOptions, ModelRef } from '../apiSetupHelpers' import { type ComponentInternalInstance, @@ -145,12 +151,9 @@ export const getModelModifiers = ( modelName: string, getter: (props: Record, key: string) => any, ): Record | undefined => { - return modelName === 'modelValue' || modelName === 'model-value' - ? getter(props, 'modelModifiers') - : getter( - props, - `${modelName}Modifiers${modelName === 'model' ? '$' : ''}`, - ) || - getter(props, `${camelize(modelName)}Modifiers`) || - getter(props, `${hyphenate(modelName)}Modifiers`) + return ( + getter(props, getModifierPropName(modelName)) || + getter(props, `${camelize(modelName)}Modifiers`) || + getter(props, `${hyphenate(modelName)}Modifiers`) + ) } diff --git a/packages/shared/src/general.ts b/packages/shared/src/general.ts index bf11ba7a293..5a6e7449340 100644 --- a/packages/shared/src/general.ts +++ b/packages/shared/src/general.ts @@ -153,6 +153,18 @@ export const toHandlerKey: ( }, ) +/** + * #13070 When v-model and v-model:model directives are used together, + * they will generate the same modelModifiers prop, + * so a `$` suffix is added to avoid conflicts. + * @private + */ +export const getModifierPropName = (name: string): string => { + return `${ + name === 'modelValue' || name === 'model-value' ? 'model' : name + }Modifiers${name === 'model' ? '$' : ''}` +} + // compare whether a value has changed, accounting for NaN. export const hasChanged = (value: any, oldValue: any): boolean => !Object.is(value, oldValue)