fix(runtime-dom): v-model should support number modifier with select tag (#2308)

close #2252
This commit is contained in:
edison 2020-10-08 03:06:41 +08:00 committed by GitHub
parent 3d3323f452
commit d744b8a2dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 107 additions and 2 deletions

View File

@ -681,6 +681,108 @@ describe('vModel', () => {
expect(bar.selected).toEqual(true)
})
it('v-model.number should work with select tag', async () => {
const component = defineComponent({
data() {
return { value: null }
},
render() {
return [
withVModel(
h(
'select',
{
value: null,
'onUpdate:modelValue': setValue.bind(this)
},
[h('option', { value: '1' }), h('option', { value: '2' })]
),
this.value,
{
number: true
}
)
]
}
})
render(h(component), root)
const input = root.querySelector('select')
const one = root.querySelector('option[value="1"]')
const data = root._vnode.component.data
one.selected = true
triggerEvent('change', input)
await nextTick()
expect(typeof data.value).toEqual('number')
expect(data.value).toEqual(1)
})
it('v-model.number should work with multiple select', async () => {
const component = defineComponent({
data() {
return { value: [] }
},
render() {
return [
withVModel(
h(
'select',
{
value: null,
multiple: true,
'onUpdate:modelValue': setValue.bind(this)
},
[h('option', { value: '1' }), h('option', { value: '2' })]
),
this.value,
{
number: true
}
)
]
}
})
render(h(component), root)
const input = root.querySelector('select')
const one = root.querySelector('option[value="1"]')
const two = root.querySelector('option[value="2"]')
const data = root._vnode.component.data
one.selected = true
two.selected = false
triggerEvent('change', input)
await nextTick()
expect(data.value).toMatchObject([1])
one.selected = false
two.selected = true
triggerEvent('change', input)
await nextTick()
expect(data.value).toMatchObject([2])
one.selected = true
two.selected = true
triggerEvent('change', input)
await nextTick()
expect(data.value).toMatchObject([1, 2])
one.selected = false
two.selected = false
data.value = [1]
await nextTick()
expect(one.selected).toEqual(true)
expect(two.selected).toEqual(false)
one.selected = false
two.selected = false
data.value = [1, 2]
await nextTick()
expect(one.selected).toEqual(true)
expect(two.selected).toEqual(true)
})
it('should work with composition session', async () => {
const component = defineComponent({
data() {

View File

@ -166,11 +166,14 @@ export const vModelRadio: ModelDirective<HTMLInputElement> = {
}
export const vModelSelect: ModelDirective<HTMLSelectElement> = {
created(el, binding, vnode) {
created(el, { modifiers: { number } }, vnode) {
addEventListener(el, 'change', () => {
const selectedVal = Array.prototype.filter
.call(el.options, (o: HTMLOptionElement) => o.selected)
.map(getValue)
.map(
(o: HTMLOptionElement) =>
number ? toNumber(getValue(o)) : getValue(o)
)
el._assign(el.multiple ? selectedVal : selectedVal[0])
})
el._assign = getModelAssigner(vnode)