理解 v-model

v-modelVue 的一个指令(内置的自定义 HTML 属性),用于在表单的 inputtextareaselect 元素上创建双向数据绑定。通过将表单输入与 Vue 数据绑定,当用户与输入字段交互时,数据会自动更新。

需要注意的是:

  1. v-model 会忽略表单元素上设置的初始值,而将 Vue 数据视为唯一真实来源。因此,初始值应在 Vuedata 选项或函数中声明。

  2. 它会根据输入类型自动选择更新方式。例如:

    • type="text" 的输入框上,会使用 value 属性和 input 事件实现双向绑定。

接下来的章节将详细解析该指令的具体应用场景。

在文本和 textarea 元素中使用 v-model

还记得我们在第 5 章《添加 Vue 组件》中使用 v-model 实现双向绑定创建自定义输入组件的内容吗?在该章的 "创建自定义输入组件" 部分,我们了解到 v-model 在输入框上的语法——<input v-model="username">——实际上是以下代码的简写形式:

<input
  v-bind:value="username"
  v-on:input="username = $event.target.value"
>

这个文本输入元素在底层做了两件事:

  1. 通过 v-bind:value 绑定值属性,从处理程序 username 获取值

  2. 通过 v-on:input 监听输入事件更新值

因此,自定义文本输入组件也必须始终在 model 属性中使用 value 属性和 input 事件,如下所示:

Vue.component('custom-input', {
  props: {
    value: String
  },
  model: {
    prop: 'value',
    event: 'input'
  },
  template: `<input v-on:input="$emit('input', $event.target.value)">`,
})

这种设计源于 v-model 的本质——由 v-bind:valuev-on:input 组合而成。同样的原理也适用于 textarea 元素:

<textarea v-model="message"></textarea>

这个 v-model textarea 元素是以下代码的简写:

<textarea
  v-bind:value="message"
  v-on:input="message = $event.target.value"
></textarea>

这个 textarea 输入元素,在幕后,绑定了 value 属性,该属性从处理程序 message 获取值,而 message 的值则来自 input 事件。因此,一个自定义的 textarea 组件也必须始终遵循 v-model textarea 元素的特性,在 model 属性中使用 value propinput 事件,如下所示:

Vue.component('custom-textarea', {
  props: {
    value: null
  },
  model: {
    prop: 'value',
    event: 'input'
  }
})

简而言之:

  • v-modelinput 输入框和 textarea 中始终绑定 value 属性

  • 通过 input 事件获取新值

  • 自定义组件必须采用相同的属性和事件

那么 v-model 在复选框和单选按钮中又是如何工作的呢?我们将在下一节深入探讨。

在复选框和单选框元素中使用 v-model

另一方面,v-model 在复选框(checkbox)和单选按钮(radio button)输入元素上的实现机制有所不同。这些元素总是绑定 checked 属性,并通过 change 事件更新布尔值。例如:

<input type="checkbox" v-model="subscribe" value="yes" name="subscribe">

实际上等价于:

<input
  type="checkbox"
  name="subscribe"
  value="yes"
  v-bind:checked="false"
  v-on:change="subscribe = $event.target.checked"
>

因此,自定义复选框组件也必须遵循相同的设计模式,在 model 属性中使用 checked 属性和 change 事件:

Vue.component('custom-checkbox', {
  props: {
    checked: Boolean,
  },
  model: {
    prop: 'checked',
    event: 'change'
  }
})

同样的原理也适用于单选按钮:

<input type="radio" v-model="answer" value="yes" name="answer">

等价于:

<input
  type="radio"
  name="answer"
  value="yes"
  v-bind:checked="answer == 'yes'"
  v-on:change="answer = $event.target.value"
>

因此自定义单选按钮组件也需要对应地实现:

Vue.component('custom-radio', {
  props: {
    checked: String,
    value: String
  },
  model: {
    prop: 'checked',
    event: 'change'
  }
})

简而言之:

  • 对于复选框(checkbox)和单选(radio)按钮,v-model 始终绑定 value 属性

  • 通过 change 事件更新值

  • 自定义组件必须采用相同的属性和事件

接下来,我们将在下一节探讨 v-modelselect 选择框元素中的工作原理。

在 select 元素中使用 v-model

与预期一致,v-modelselect 选择框元素中的实现机制也是通过绑定 value 属性,并在 change 事件中获取选中值。例如:

<select v-model="favourite" name="favourite">
  <!-- 选项内容 -->
</select>

这实际上是以下写法的语法糖:

<select
  v-bind:value="favourite"
  v-on:change="favourite = $event.target.value"
  name="favourite"
>
  <!-- 选项内容 -->
</select>

因此,自定义选择框(checkbox)组件也必须遵循相同的设计模式,在 model 属性中使用 value 属性和 change 事件:

Vue.component('custom-select', {
  props: {
    value: String
  },
  model: {
    prop: 'value',
    event: 'change'
  }
})

由此可见:

  1. v-model 本质上是 v-bindv-on 的组合语法糖

    • v-bind 负责将值绑定到标记

    • v-on 监听用户输入事件(可能是 changeinput 事件)来更新数据

  2. 作为 Vue/Nuxt 开发者,理解其底层原理至关重要

本节涉及的完整示例代码可在 GitHub 仓库的 /chapter-7/vue/html/ 目录中找到。

既然我们已经了解了 v-model 指令在各种表单元素中的工作原理,接下来让我们在表单中使用这些元素,并在下一节中实现表单验证功能。