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)