This commit is contained in:
yangxiuxiu 2025-05-05 20:38:32 +00:00 committed by GitHub
commit 2c8e3a6a99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 63 additions and 11 deletions

View File

@ -1,5 +1,6 @@
import {
type VNode,
computed,
defineComponent,
h,
nextTick,
@ -1409,6 +1410,51 @@ describe('vModel', () => {
expect(bar.selected).toEqual(true)
})
it('multiple select (v-model has custom setter)', async () => {
const selected = ref([])
const multipleSelected = computed({
get() {
return selected.value
},
set(newVal) {
selected.value = newVal.slice(0, 1)
},
})
const setValue = (v: any) => {
multipleSelected.value = v
}
const component = defineComponent({
render() {
return [
withVModel(
h(
'select',
{
multiple: true,
'onUpdate:modelValue': setValue,
},
[h('option', { value: '1' }), h('option', { value: '2' })],
),
multipleSelected.value,
),
]
},
})
render(h(component), root)
await nextTick()
const select = root.querySelector('select')
const [foo, bar] = root.querySelectorAll('option')
foo.selected = true
bar.selected = true
triggerEvent('change', select)
await nextTick()
expect(selected.value).toEqual(['1'])
expect(foo.selected).toEqual(true)
expect(bar.selected).toEqual(false)
})
// #10503
test('equal value with a leading 0 should trigger update.', async () => {
const setNum = function (this: any, value: any) {

View File

@ -4,6 +4,7 @@ import {
type ObjectDirective,
type VNode,
nextTick,
toRaw,
warn,
} from '@vue/runtime-core'
import { addEventListener } from '../modules/events'
@ -38,9 +39,15 @@ function onCompositionEnd(e: Event) {
}
const assignKey: unique symbol = Symbol('_assign')
const assignValueKey: unique symbol = Symbol('_value')
const assigningKey: unique symbol = Symbol('_assigning')
type ModelDirective<T, Modifiers extends string = string> = ObjectDirective<
T & { [assignKey]: AssignerFn; _assigning?: boolean },
T & {
[assignKey]: AssignerFn
[assignValueKey]: any
[assigningKey]?: boolean
},
any,
Modifiers
>
@ -210,16 +217,15 @@ export const vModelSelect: ModelDirective<HTMLSelectElement, 'number'> = {
.map((o: HTMLOptionElement) =>
number ? looseToNumber(getValue(o)) : getValue(o),
)
el[assignKey](
el.multiple
const value = (el[assignValueKey] = el.multiple
? isSetModel
? new Set(selectedVal)
: selectedVal
: selectedVal[0],
)
el._assigning = true
: selectedVal[0])
el[assignKey](value)
el[assigningKey] = true
nextTick(() => {
el._assigning = false
el[assigningKey] = false
})
})
el[assignKey] = getModelAssigner(vnode)
@ -233,7 +239,7 @@ export const vModelSelect: ModelDirective<HTMLSelectElement, 'number'> = {
el[assignKey] = getModelAssigner(vnode)
},
updated(el, { value }) {
if (!el._assigning) {
if (!el[assigningKey] || toRaw(value) !== el[assignValueKey]) {
setSelected(el, value)
}
},