Luna Tech

Tutorials For Dummies.

Vue: Form Input Bindings

2022-03-20


0. Intro

Reference

Useful video

如果不用 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:

v-model will ignore the initial value, checked or selected 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 the data 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 an input event listener and value binding instead of using v-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-valuefalse-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 and false-value are Vue-specific attributes that only works with v-model. The true-value and false-value attributes don’t affect the input’s value 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 each input event (with the exception of IME composition as stated above ). You can add the lazy modifier to instead sync after change 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" />

5. v-model with Components

Component Events | Vue.js (vuejs.org)