1
- import { checkIsRefObj , isArray , isString , isUndefined } from '../utils'
1
+ import { checkIsRefObj , getValueFromObject , isArray , isString , isUndefined , setValueToObject } from '../utils'
2
2
import type { Ref } from '@vue/composition-api'
3
3
import type { VNodeData } from 'vue'
4
4
import { ConfigType , TagType } from '../type'
5
5
import { getCurrentInstance } from '../runtime'
6
6
7
7
const IME_START_KEY = '__ime_start__'
8
8
9
- type vModelBinding = string |
10
- Ref < unknown > |
9
+ type vModelBinding =
10
+ string | Ref < unknown > |
11
11
[ string | Ref < unknown > ] |
12
12
[ string | Ref < unknown > , string [ ] ] |
13
13
[ string | Ref < unknown > , string , string [ ] ]
@@ -19,61 +19,83 @@ const dealWithVModel = (
19
19
vNodeData : VNodeData ,
20
20
isHTMLElement : boolean
21
21
) => {
22
- let bindingTarget : string | Ref < unknown >
23
- // let argument: string | undefined
22
+ let bindingKeyPathOrRef : string | Ref < unknown >
23
+ let argument : string | undefined
24
24
let modifiers : string [ ] = [ ]
25
25
26
26
if ( isString ( bindingExpression ) || checkIsRefObj ( bindingExpression ) ) {
27
- bindingTarget = bindingExpression
27
+ bindingKeyPathOrRef = bindingExpression
28
28
} else if ( isArray ( bindingExpression ) ) {
29
- bindingTarget = bindingExpression [ 0 ]
29
+ bindingKeyPathOrRef = bindingExpression [ 0 ]
30
30
if ( bindingExpression . length === 2 ) {
31
- modifiers = bindingExpression [ 1 ]
31
+ if ( isArray ( bindingExpression [ 1 ] ) ) {
32
+ modifiers = bindingExpression [ 1 ]
33
+ } else if ( isString ( bindingExpression [ 1 ] ) ) {
34
+ argument = bindingExpression [ 1 ]
35
+ }
32
36
} else if ( bindingExpression . length === 3 ) {
33
- // argument = bindingExpression[1]
37
+ argument = bindingExpression [ 1 ]
34
38
modifiers = bindingExpression [ 2 ]
35
39
}
36
40
}
37
41
38
42
const instance = getCurrentInstance ( )
43
+ const getBindingValue = ( ) => {
44
+ // v-model='a.b.c'
45
+ if ( isString ( bindingKeyPathOrRef ) ) {
46
+ return getValueFromObject ( instance , bindingKeyPathOrRef )
47
+ }
48
+
49
+ // v-model={[xxRef, 'a.b.c']}
50
+ if ( argument ) {
51
+ return getValueFromObject ( bindingKeyPathOrRef . value , argument )
52
+ }
53
+
54
+ // v-model={xxRef}
55
+ return bindingKeyPathOrRef . value
56
+ }
39
57
58
+ const emitValue = ( payload : unknown ) => {
59
+ if ( isString ( bindingKeyPathOrRef ) ) {
60
+ setValueToObject ( instance , bindingKeyPathOrRef , payload )
61
+ // Vue.set(instance, bindingKeyPathOrRef, payload)
62
+ } else if ( argument ) {
63
+ setValueToObject ( bindingKeyPathOrRef . value , argument , payload )
64
+ // Vue.set(bindingKeyPathOrRef.value as any, argument, payload)
65
+ } else {
66
+ bindingKeyPathOrRef . value = payload
67
+ }
68
+ }
69
+
70
+ // <select />.
40
71
if ( tag === 'select' ) {
41
- vNodeData . domProps . value = isString ( bindingTarget )
42
- ? instance [ bindingTarget ]
43
- : bindingTarget . value
72
+ vNodeData . domProps . value = getBindingValue ( )
44
73
vNodeData . on . change = ( event : Event ) => {
45
74
const target = event . target as HTMLSelectElement
46
- if ( isString ( bindingTarget ) ) {
47
- instance [ bindingTarget ] = target . value
48
- } else {
49
- bindingTarget . value = target . value
50
- }
75
+ const payload = target . value
76
+ emitValue ( payload )
51
77
}
52
78
return
53
79
}
54
80
81
+ // <input radio|checkbox />.
55
82
if ( tag === 'input' ) {
56
83
const inputType = config . type // 'file', 'text', 'number', .ect.
57
84
58
85
// Skip unsupported input.
59
- const isSkippedInput = / b u t t o n | f i l e | s u b m i t | r e s e t / . test ( inputType )
60
- if ( isSkippedInput ) {
86
+ const isSkippedType = / b u t t o n | f i l e | s u b m i t | r e s e t / . test ( inputType )
87
+ if ( isSkippedType ) {
61
88
return
62
89
}
63
90
64
91
// Radio.
65
92
const isRadioInput = inputType === 'radio'
66
93
if ( isRadioInput ) {
67
- vNodeData . domProps . checked = isString ( bindingTarget )
68
- ? instance [ bindingTarget ] === config . value
69
- : bindingTarget . value === config . value
94
+ vNodeData . domProps . checked = getBindingValue ( ) === config . value
70
95
vNodeData . on . change = ( event : Event ) => {
71
96
const target = event . target as HTMLInputElement
72
- if ( isString ( bindingTarget ) ) {
73
- instance [ bindingTarget ] = target . value
74
- } else {
75
- bindingTarget . value = target . value
76
- }
97
+ const payload = target . value
98
+ emitValue ( payload )
77
99
}
78
100
return
79
101
}
@@ -100,70 +122,49 @@ const dealWithVModel = (
100
122
const target = event . target as HTMLInputElement
101
123
const isValueSpecified = ! isUndefined ( config . value )
102
124
const newCheckStatus = target . checked
103
- if ( isString ( bindingTarget ) ) {
104
- instance [ bindingTarget ] = isValueSpecified
105
- ? target . value
106
- : newCheckStatus ? checkboxDefaultValue : undefined
107
- } else {
108
- bindingTarget . value = isValueSpecified
109
- ? target . value
110
- : newCheckStatus ? checkboxDefaultValue : undefined
111
- }
125
+ const payload = isValueSpecified
126
+ ? target . value
127
+ : newCheckStatus ? checkboxDefaultValue : undefined
128
+ emitValue ( payload )
112
129
}
113
130
}
114
131
115
- let bindingValue : unknown
116
- if ( isString ( bindingTarget ) ) {
117
- bindingValue = instance [ bindingTarget ]
118
- } else {
119
- bindingValue = bindingTarget . value
120
- }
132
+ const bindingValue : unknown = getBindingValue ( )
121
133
122
134
if ( isArray ( bindingValue ) ) {
123
- // Array binding.
124
135
arrayBindingExec ( bindingValue )
125
136
} else {
126
- // Basic binding.
127
137
basicBindingExec ( bindingValue )
128
138
}
129
139
return
130
140
}
131
141
}
132
142
133
- // Others are treated as text fields .
143
+ // <input /> | <textarea /> .
134
144
if ( tag === 'input' || tag === 'textarea' ) {
135
145
const isDirectInput = modifiers . includes ( 'direct' )
136
146
const isLazyInput = modifiers . includes ( 'lazy' )
137
- const emitValue = ( value : string ) => {
147
+ const emit = ( value : string ) => {
138
148
const hasNumberModifier = modifiers . includes ( 'number' )
139
149
const hasTrimModifier = modifiers . includes ( 'trim' )
140
- const newValue = hasNumberModifier
150
+ const payload = hasNumberModifier
141
151
? parseFloat ( value )
142
152
: hasTrimModifier
143
153
? value . trim ( )
144
154
: value
145
155
146
- if ( isString ( bindingTarget ) ) {
147
- instance [ bindingTarget ] = newValue
148
- } else {
149
- bindingTarget . value = newValue
150
- }
156
+ emitValue ( payload )
151
157
}
152
158
153
159
vNodeData . attrs [ IME_START_KEY ] = false
154
- vNodeData . domProps . value = isString ( bindingTarget )
155
- ? instance [ bindingTarget ]
156
- : bindingTarget . value
160
+ vNodeData . domProps . value = getBindingValue ( )
157
161
vNodeData . on . input = ( event : Event ) => {
158
- if (
159
- isLazyInput ||
160
- ( ! isDirectInput && vNodeData . attrs [ IME_START_KEY ] )
161
- ) {
162
+ if ( isLazyInput || ( ! isDirectInput && vNodeData . attrs [ IME_START_KEY ] ) ) {
162
163
return
163
164
}
164
165
165
166
const target = event . target as HTMLInputElement
166
- emitValue ( target . value )
167
+ emit ( target . value )
167
168
}
168
169
169
170
if ( isLazyInput ) {
@@ -190,16 +191,9 @@ const dealWithVModel = (
190
191
191
192
// v-model on component.
192
193
if ( ! isHTMLElement ) {
193
- const instance = getCurrentInstance ( )
194
- vNodeData . props . value = isString ( bindingTarget )
195
- ? instance [ bindingTarget ]
196
- : bindingTarget . value
197
- vNodeData . on . input = ( value ) => {
198
- if ( isString ( bindingTarget ) ) {
199
- instance [ bindingTarget ] = value
200
- } else {
201
- bindingTarget . value = value
202
- }
194
+ vNodeData . props . value = getBindingValue ( )
195
+ vNodeData . on . input = ( payload ) => {
196
+ emitValue ( payload )
203
197
}
204
198
}
205
199
}
0 commit comments