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 use- valueproperty and- inputevent;
- <input type="checkbox">and- <input type="radio">use- checkedproperty and- changeevent;
- <select>use- valueas a prop and- changeas an event.
v-modelwill ignore the initialvalue,checkedorselectedattributes 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 thedataoption.
需要注意的是,我们要手动设置 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-modeldoesn’t get updated during IME composition. If you want to respond to these updates as well, use aninputevent listener andvaluebinding 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-modelexpression 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-valueandfalse-valueare Vue-specific attributes that only works withv-model. Thetrue-valueandfalse-valueattributes don’t affect the input’svalueattribute, 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-modelsyncs the input with the data after eachinputevent (with the exception of IME composition as stated above ). You can add thelazymodifier to instead sync afterchangeevents
<!-- 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" />