双向数据绑定
本节讲解 Vue 中比较重要的一个指令— v-model 双向数据绑定指令。双向数据绑定的概念如下。
-
数据层(M 层)发生变化会影响视图层(V 层)改变。
-
视图层(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 所示。

此时将文本框的值修改成 “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 所示。

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 所示。

使用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 所示。

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>
代码解析如下。
-
视图层 v-model 定义的属性值必须在 M 层的 data 中定义,否则程序报错。
-
btn 方法在 methods 中定义。
-
要点:btn 方法中用到了 data 中的数据,如 num1、num2、res,需要注意的是,在 methods 中调用 data 中的数据,必须要加 this。
this 表示当前的 vm 实例,在控制台中 console.log(vm) 打印的实例对象如图 1-13 所示。

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