Vue: Form Input Bindings
2022-03-20
0. Intro
如果不用 v-model 的话,我们要通过 event listener 和 value binding 来完成 2-way binding,如下:
<input :value="text" @input="event => text = event.target.value" />
使用 v-model
<input v-model="text" />
1. 什么时候可以使用 v-model?
不同的 input type element,<textarea>
, <select>
都可以用 v-model,比如,而且它还很智能,会根据不同的 element 来匹配 DOM property 和 event:
<input>
with text types and<textarea>
elements usevalue
property andinput
event;<input type="checkbox">
and<input type="radio">
usechecked
property andchange
event;<select>
usevalue
as a prop andchange
as an event.
v-model
will ignore the initialvalue
,checked
orselected
attributes found on any form elements. It will always treat the current bound JavaScript state as the source of truth. You should declare the initial value on the JavaScript side, using thedata
option.
需要注意的是,我们要手动设置 initial value,因为默认的 value 会被忽略。
2. Examples
Example - Text
<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="edit me" />
For languages that require an IME (Chinese, Japanese, Korean etc.), you’ll notice that
v-model
doesn’t get updated during IME composition. If you want to respond to these updates as well, use aninput
event listener andvalue
binding instead of usingv-model
.
比如中文需要用拼音,那么只有打完字才会 bind,假如你希望对拼音做出反应,需要用 input + value binding 的方式来做 data binding,因为 v-model 不支持这个。
Example - Multiline Text
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
<!-- bad 这种写法没用,需要用 v-model -->
<textarea>{{ text }}</textarea>
<!-- good -->
<textarea v-model="text"></textarea>
Example - Checkbox
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
Example - Multiple Checkboxes
我们可以 bind 多个 checkbox 到一个 array 或者 set
,下面的例子中,checkedNames
array 永远只包含当前勾选的 checkbox values。
<div>Checked names: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
export default {
data() {
return {
checkedNames: []
}
}
}
Example - Radio
<div>Picked: {{ picked }}</div>
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
Example - Select (single)
<div>Selected: {{ selected }}</div>
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
If the initial value of your
v-model
expression does not match any of the options, the<select>
element will render in an “unselected” state. On iOS this will cause the user not being able to select the first item because iOS does not fire a change event in this case. It is therefore recommended to provide a disabled option with an empty value, as demonstrated in the example above.假如初始值没有任何 match option,iOS 会出现问题,所以最好加个 disabled option with empty value。
Example - Select (Multiple)
<div>Selected: {{ selected }}</div>
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
我们还可以动态渲染 options,用 v-for
就可以了:
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
</option>
</select>
<div>Selected: {{ selected }}</div>
export default {
data() {
return {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
}
}
3. Value Bindings
radio, checkbox 和 select option 的 v-model binding value 大部分时候都是固定的 string(或者 boolean for checkbox)。
<!-- `picked` is a string "a" when checked -->
<input type="radio" v-model="picked" value="a" />
<!-- `toggle` is either true or false -->
<input type="checkbox" v-model="toggle" />
<!-- `selected` is a string "abc" when the first option is selected -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>
但有些时候我们想要 bind value 到一个当前 active instance 的动态 property 上,那么就要用到 v-bind
了。v-bind
还可以让我们 bind input value to non-string values.
Tips:使用 v-bind
的时候可以用 :xx
这个 shorthand。
Example - checkbox with static string
true-value
和 false-value
只能跟 v-model
一起使用。
Here the toggle
property’s value will be set to 'yes'
when the box is checked, and set to 'no'
when unchecked.
true-value
andfalse-value
are Vue-specific attributes that only works withv-model
. Thetrue-value
andfalse-value
attributes don’t affect the input’svalue
attribute, because browsers don’t include unchecked boxes in form submissions.To guarantee that one of two values is submitted in a form (e.g. “yes” or “no”), use radio inputs instead.
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no" />
Example - checkbox with dynamic value
<input
type="checkbox"
v-model="toggle"
:true-value="dynamicTrueValue"
:false-value="dynamicFalseValue" />
Example - radio with dynamic value
pick
will be set to the value of first
when the first radio input is checked, and set to the value of second
when the second one is checked.
<input type="radio" v-model="pick" :value="first" />
<input type="radio" v-model="pick" :value="second" />
Example - select options with dynamic value
v-model
也支持 non-string value binding,当 option is selected, selected
will be set to the object literal value of { number: 123 }
.
<select v-model="selected">
<!-- inline object literal -->
<option :value="{ number: 123 }">123</option>
</select>
4. Modifiers
.lazy
加上这个 modifier,就是在 change event 之后再 sync data,而不是 input event 之后就直接 sync。
By default,
v-model
syncs the input with the data after eachinput
event (with the exception of IME composition as stated above ). You can add thelazy
modifier to instead sync afterchange
events
<!-- synced after "change" instead of "input" -->
<input v-model.lazy="msg" />
.number
假如你想要 user input 自动 typecast 为 number,可以用这个 modifier。
If the value cannot be parsed with parseFloat()
, then the original value is used instead.
The number
modifier is applied automatically if the input has type="number"
.
<input v-model.number="age" />
.trim
自动去掉 input 前后的空格,挺有用的。
<input v-model.trim="msg" />