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 { import {
type VNode, type VNode,
computed,
defineComponent, defineComponent,
h, h,
nextTick, nextTick,
@ -1409,6 +1410,51 @@ describe('vModel', () => {
expect(bar.selected).toEqual(true) 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 // #10503
test('equal value with a leading 0 should trigger update.', async () => { test('equal value with a leading 0 should trigger update.', async () => {
const setNum = function (this: any, value: any) { const setNum = function (this: any, value: any) {

View File

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