mirror of https://github.com/vuejs/core.git
fix(defineModel): support kebab-case/camelCase mismatches (#9950)
This commit is contained in:
parent
f300a4001e
commit
10ccb9bfa0
|
@ -314,6 +314,84 @@ describe('SFC <script setup> helpers', () => {
|
|||
expect(serializeInner(root)).toBe('bar')
|
||||
})
|
||||
|
||||
test('kebab-case v-model (should not be local)', async () => {
|
||||
let foo: any
|
||||
|
||||
const compRender = vi.fn()
|
||||
const Comp = defineComponent({
|
||||
props: ['fooBar'],
|
||||
emits: ['update:fooBar'],
|
||||
setup(props) {
|
||||
foo = useModel(props, 'fooBar')
|
||||
return () => {
|
||||
compRender()
|
||||
return foo.value
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const updateFooBar = vi.fn()
|
||||
const root = nodeOps.createElement('div')
|
||||
// v-model:foo-bar compiles to foo-bar and onUpdate:fooBar
|
||||
render(
|
||||
h(Comp, { 'foo-bar': 'initial', 'onUpdate:fooBar': updateFooBar }),
|
||||
root,
|
||||
)
|
||||
expect(compRender).toBeCalledTimes(1)
|
||||
expect(serializeInner(root)).toBe('initial')
|
||||
|
||||
expect(foo.value).toBe('initial')
|
||||
foo.value = 'bar'
|
||||
// should not be using local mode, so nothing should actually change
|
||||
expect(foo.value).toBe('initial')
|
||||
|
||||
await nextTick()
|
||||
expect(compRender).toBeCalledTimes(1)
|
||||
expect(updateFooBar).toBeCalledTimes(1)
|
||||
expect(updateFooBar).toHaveBeenCalledWith('bar')
|
||||
expect(foo.value).toBe('initial')
|
||||
expect(serializeInner(root)).toBe('initial')
|
||||
})
|
||||
|
||||
test('kebab-case update listener (should not be local)', async () => {
|
||||
let foo: any
|
||||
|
||||
const compRender = vi.fn()
|
||||
const Comp = defineComponent({
|
||||
props: ['fooBar'],
|
||||
emits: ['update:fooBar'],
|
||||
setup(props) {
|
||||
foo = useModel(props, 'fooBar')
|
||||
return () => {
|
||||
compRender()
|
||||
return foo.value
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const updateFooBar = vi.fn()
|
||||
const root = nodeOps.createElement('div')
|
||||
// The template compiler won't create hyphenated listeners, but it could have been passed manually
|
||||
render(
|
||||
h(Comp, { 'foo-bar': 'initial', 'onUpdate:foo-bar': updateFooBar }),
|
||||
root,
|
||||
)
|
||||
expect(compRender).toBeCalledTimes(1)
|
||||
expect(serializeInner(root)).toBe('initial')
|
||||
|
||||
expect(foo.value).toBe('initial')
|
||||
foo.value = 'bar'
|
||||
// should not be using local mode, so nothing should actually change
|
||||
expect(foo.value).toBe('initial')
|
||||
|
||||
await nextTick()
|
||||
expect(compRender).toBeCalledTimes(1)
|
||||
expect(updateFooBar).toBeCalledTimes(1)
|
||||
expect(updateFooBar).toHaveBeenCalledWith('bar')
|
||||
expect(foo.value).toBe('initial')
|
||||
expect(serializeInner(root)).toBe('initial')
|
||||
})
|
||||
|
||||
test('default value', async () => {
|
||||
let count: any
|
||||
const inc = () => {
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
camelize,
|
||||
extend,
|
||||
hasChanged,
|
||||
hyphenate,
|
||||
isArray,
|
||||
isFunction,
|
||||
isPromise,
|
||||
|
@ -382,6 +383,7 @@ export function useModel(
|
|||
}
|
||||
|
||||
const camelizedName = camelize(name)
|
||||
const hyphenatedName = hyphenate(name)
|
||||
|
||||
const res = customRef((track, trigger) => {
|
||||
let localValue: any
|
||||
|
@ -403,9 +405,12 @@ export function useModel(
|
|||
!(
|
||||
rawProps &&
|
||||
// check if parent has passed v-model
|
||||
(name in rawProps || camelizedName in rawProps) &&
|
||||
(name in rawProps ||
|
||||
camelizedName in rawProps ||
|
||||
hyphenatedName in rawProps) &&
|
||||
(`onUpdate:${name}` in rawProps ||
|
||||
`onUpdate:${camelizedName}` in rawProps)
|
||||
`onUpdate:${camelizedName}` in rawProps ||
|
||||
`onUpdate:${hyphenatedName}` in rawProps)
|
||||
) &&
|
||||
hasChanged(value, localValue)
|
||||
) {
|
||||
|
|
Loading…
Reference in New Issue