1 监视属性[¶](#1 监视属性¶)
监视属性是一种用于监视某个数据的变化,并触发相应的回调函数执行的机制。在vue内部,使用"wathch"关键字用于声明监视属性。
1.1 基本用法[¶](#1.1 基本用法¶)
(1)添加watch属性,值为一个对象。对象的属性名就是要监视的数据,属性值为回调函数,每当这个属性名对应的值发生变化,就会触发该回调函数执行
(2)回调函数有2个参数:
newVal:数据发生改变后的值
oldVal:数据发生改变前的值
例如,我们定义一个变量num,在页面中添加一个按钮,每点击一次按钮,num的值加1,另外,每次在num的值发生改变时,控制台输出提示。
<!-- 准备好一个容器-->
<div id="root">
<h2>num的值为:{{num}}</h2>
<button @click="changeNum">点击num+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
num: 0
},
methods: {
changeNum(){
this.num = this.num + 1
}
},
watch:{
num(newVal, oldVal){ // newVal为修改后的值, oldVal为修改前的值
console.log('num的值发生了变化')
console.log(newVal,oldVal)
}
}
})
</script>
1.2 监听对象内部属性的变化[¶](#1.2 监听对象内部属性的变化¶)
前面的例子只是监听data中的第一层数据,如果要监听多层次的数据,例如a.b.c,则属性名需要用引号包裹起来.
<div id="root">
<h2>a的值为:{{num.a}}</h2>
<h2>num的值为:{{num}}</h2>
<button @click="changeA">点击a+1</button>
<button @click="changeNum">修改num</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
num: {
a: 0,
b: 0
}
},
methods: {
changeA(){
this.num.a = this.num.a + 1
},
changeNum(){
this.num = {a:100, b:200}
}
},
watch:{
"num.a"(newVal, oldVal){ // 注意:此时,因为a是对象内部变量,所以a必须用"num.a"的方式用双引号包裹
console.log('a的值发生了变化')
console.log(newVal,oldVal)
},
num(newVal, oldVal){ // newVal为修改后的值, oldVal为修改前的值
console.log('num的值发生了变化')
console.log(newVal,oldVal)
}
}
})
</script>
如下图所示,第一次点击"点击a+1"按钮,a的值加了1,控制台输出了两行;第一次点击"修改num"按钮,因为a的值也同时发生改变,所以a的监视属性也触发,因为num完整修改了,所以,num的监视属性也修改了。所以会有4行输出结果在控制台。
1.3 深度监听[¶](#1.3 深度监听¶)
监视属性只能监听到当前对象值的变化,而对象内部的属性变化不会监听到,前面1.2节我们监听了num和num.a,修改了num.a并不会触发监听num的监听属性。 想要监听对象内部的属性值变化,需要进行相应的配置。
-
deep:深度监听,默认false,当对象内部深层属性变量发生修改时,是否触发
-
handler:回调函数
-
immediate: 页面初始化时是否触发回调,默认false
如下所示,我们只监听num对象,但修改num对象内部的变量a时,num的监听属性也被触发,这就是深度监听的作用:
<div id="root">
<h2>a的值为:{{num.a}}</h2>
<button @click="changeA">点击a+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
num: {
a: 0,
b: 0
}
},
methods: {
changeA(){
this.num.a = this.num.a + 1 // 注意:此处修改的是a的值,而不是整个num
}
},
watch:{
num: { // 监听num对象
deep: true, // 深度监听
handler:function(newVal,oldVal){ // 监听属性的回调方法
console.log('num的值发生了变化')
console.log(this.num.a, this.num.b)
},
immediate:true // 页面初始化时是否触发回调
}
}
})
</script>
点击一次按钮,控制台输出两次,第一次是因为imediate设置为了true,当页面初始化时,会自动出发一次num的监视属性,第一次是点击按钮触发。
1.4 监视属性的简写[¶](#1.4 监视属性的简写¶)
在1.3节说到,监视属性有三种属性,即deep、imediate、handler,当deep和imediate两个属性不需要使用(使用默认值时),可以使用简写形式,下方代码中,被注释的完整形式和简写形式作用是一样的:
<div id="root">
<h2>a的值为:{{num}}</h2>
<button @click="changeNum">点击a+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
num: 0
},
methods: {
changeNum(){
this.num = this.num + 1 // 注意:此处修改的是a的值,而不是整个num
}
},
watch:{
// 完整写法
// num: { // 监听num对象
// deep: false, // 深度监听
// immediate:false,
// handler:function(newVal,oldVal){ // 监听属性的回调方法
// console.log('num的值发生了变化')
// console.log(newVal,oldVal)
// },
// }
// 简写形式
num(newVal,oldVal){
console.log('num的值发生了变化')
console.log(newVal,oldVal)
}
}
})
</script>
1.5 创建监视属性的另一种方式[¶](#1.5 创建监视属性的另一种方式¶)
监视属性也可以在创建完vue实例之后再添加:
<div id="root">
<h2>a的值为:{{num}}</h2>
<button @click="changeNum">点击a+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
num: 0
},
methods: {
changeNum(){
this.num = this.num + 1 // 注意:此处修改的是a的值,而不是整个num
}
},
})
// 为num添加监视属性
vm.$watch('num',{ // 指定监视num
immediate:true, //初始化时让handler调用一下
handler(newValue,oldValue){
console.log('num被修改了',newValue,oldValue)
}
})
</script>
2 计算属性与监视属性的对比[¶](#2 计算属性与监视属性的对比¶)
- 计算属性能完成的功能,监视属性都能完成
- 监视属性能完成的部分功能,计算属性不一定能完成,例如涉及异步操作的功能
- 如果两者都能完成的功能,建议使用计算属性,效率更高
如下所示,连个输入框分别双向绑定两个变量:num1和num2,在输入框下方输出两个变量的和,要求无论哪个变量发生修改,延迟3秒后,再求和并输出。因为涉及的延迟输出,计算属性就不能完成了,这时候要使用监视属性:
<div id="root">
num1:<input type="text" v-model="num1"> <br/><br/>
num2:<input type="text" v-model="num2"> <br/><br/>
sum:<span>{{sum}}</span> <br/><br/>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
num1: 0,
num2: 0,
sum: 0
},
watch:{
num1(val){
setTimeout(()=>{
console.log(this)
this.sum = parseInt(this.num1) + parseInt(this.num2)
},3000);
},
num1(val){
setTimeout(()=>{
console.log(this)
this.sum = parseInt(this.num1) + parseInt(this.num2)
},3000);
},
}
})
</script>