双向数据绑定

本节讲解 Vue 中比较重要的一个指令— v-model 双向数据绑定指令。双向数据绑定的概念如下。

  1. 数据层(M 层)发生变化会影响视图层(V 层)改变。

  2. 视图层(V 层)发生变化会影响数据层(M 层)改变。

下面开始 v-model 指令的学习。当前有这样一个需求,即把 M 层中的 msg 数据渲染到 input 文本框中,代码如下。

M 层代码如下。

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'Hello World'
        },
        methods: {}
    });
</script>

先不使用 v-model 指令,按照以前的写法可以使用 v-bind 属性绑定的形式,代码如下。

视图层代码如下。

<div id="app" v-cloak>
    <h1>插值表达式:{{ msg }}</h1>
    <input type="text" :value="msg">
</div>

使用 v-bind 属性绑定的形式,可以把 msg 数据渲染出来,但是当修改文本框中的内容时,M 层数据不会改变,如图 1-9 所示。

image 2025 02 10 17 49 34 355
Figure 1. 图1-9 h1标签渲染结果1

此时将文本框的值修改成 “Hello Vue”,但插值表达式渲染出来的仍然是 “Hello World”,说明 M 层的数据并没有随着 V 层数据的改变而改变,正确的代码如下。

<div id="app" v-cloak>
    <h1>插值表达式:{{ msg }}</h1>
    <input type="text" v-model="msg">
</div>

使用 v-model 代替 v-bind,当文本框的值修改成 “Hello Vue” 时,插值表达式的渲染结果也同时修改成 “Hello Vue”,如图 1-10 所示。

image 2025 02 10 17 53 13 276
Figure 2. 图1-10 h1标签渲染结果2

v-model 只能运用到表单元素,只有表单元素是用户可以操作的。

v-model修饰符

v-model 还可以添加修饰符,例如数字修饰符 “.number”,表示用户只能输入数字,代码如下。

M 层代码如下。

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'Hello World',
            num: 1,
            num1: ''
        },
        methods: {}
    });
</script>

视图层代码如下。

<div id="app" v-cloak>
    <input type="text" v-model.number="num">
</div>

常用的修饰符还有过滤首尾空格 “.trim”,代码如下。

视图层代码如下。

<div id="app" v-cloak>
    <!-- 绑定 num1,使用 .trim 修饰符去除首尾空格 -->
    <input type="text" v-model.trim="num1">
</div>

本节最后一个知识点是 .lazy 修饰符的使用,其表示内容发生变化,并且在失去焦点时触发,代码如下。

<div id="app" v-cloak>
    <h1>插值表达式:{{ num }}</h1>
    <!-- 绑定 num,使用 .lazy 修饰符在失去焦点时触发更新 -->
    <input type="text" v-model.lazy="num">
</div>

当文本框的值发生变化时,插值表达式的渲染结果并不会立即改变,而是要等到文本框失去焦点后才改变,如图 1-11 所示。

image 2025 02 10 18 05 46 514
Figure 3. 图1-11 插值表达式渲染结果

使用v-model实现计算器案例

本节使用 v-model 实现简单的计算器功能,代码如下。

视图层代码如下。

<div id="app" v-cloak>
  <input type="text" v-model="num1" placeholder="请输入第1个数字">

  <select v-model="sel">
    <option value="+">+</option>
    <option value="-">-</option>
    <option value="*">*</option>
    <option value="/">/</option>
  </select>

  <input type="text" v-model="num2" placeholder="请输入第2个数字">

  <input type="button" value="=" @click="btn">

  <input type="text" v-model="res">
</div>

运行代码,计算器效果如图 1-12 所示。

image 2025 02 10 18 09 34 990
Figure 4. 图1-12 计算器前端效果图

M 层代码如下。

<script>
  var vm = new Vue({
    el: '#app',
    data: {
      num1: null,
      sel: '+',
      num2: null,
      res: null
    },
    methods: {
      btn() {
        if (this.sel == "+") {
          this.res = parseInt(this.num1) + parseInt(this.num2);
        } else if (this.sel == "-") {
          this.res = parseInt(this.num1) - parseInt(this.num2);
        } else if (this.sel == "*") {
          this.res = parseInt(this.num1) * parseInt(this.num2);
        } else {
          this.res = parseInt(this.num1) / parseInt(this.num2);
        }
      }
    }
  })
</script>

代码解析如下。

  1. 视图层 v-model 定义的属性值必须在 M 层的 data 中定义,否则程序报错。

  2. btn 方法在 methods 中定义。

  3. 要点:btn 方法中用到了 data 中的数据,如 num1、num2、res,需要注意的是,在 methods 中调用 data 中的数据,必须要加 this。

this 表示当前的 vm 实例,在控制台中 console.log(vm) 打印的实例对象如图 1-13 所示。

image 2025 02 10 18 11 57 646
Figure 5. 图1-13 打印vm实例对象

打印 vm 实例对象发现,btn 方法和 num1、num2 等属于平级关系,所以在 btn 方法中使用 num1、num2 时,需要使用 this.num1、this.num2。