目录
- 一、基本使用
- 1.1 watch配置监视
- 1.2 vm.$watch动态监视
- 1.3 深度监视(deep watch)
- 1.4 简写形式
- 二、computed和watch的对比
- 2.1 使用watch实现setTimeout操作
- 2.2 用computed无法实现setTimeout
- 三、其他注意事项
- 3.1 vue devtools的bug
- 3.2 @xxx=yyy格式
- 3.3 将window传入data中
Vue
提供了一种更通用的方式来观察和响应 Vue实例上的数据变动:侦听属性,也成为监视属性
。
一、基本使用
监视属性watch
:
- 当被监视的属性变化时,回调函数
handler
自动调用,进行相关操作。 - 监视的属性必须存在,才能进行监视。
- 监视的两种写法
a.new Vue
时传入watch
配置
b. 通过vm.$watch
来动态实现监视
1.1 watch配置监视
下面案例中,我们通过watch
配置属性来给isHuoguo
添加监视,当isHuoguo
发生变化时,所配置的handler()
函数会调用。
注意:这里有一个属性immediate
,其默认值为false
。当配置为true
时,页面初始化时,让handler
调用一下。
<div id="root">
<h2>今天我们去吃{{info}}</h2>
<button @click="change">切换</button>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
isHuoguo:true
},
computed:{
info() {
return this.isHuoguo?'火锅':'南京大排档';
}
},
methods: {
change() {
this.isHuoguo = !this.isHuoguo;
}
},
watch: {
isHuoguo:{
immediate:true,//默认为false,初始化时,让handler调用一下。
handler(newValue, oldValue) {
console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
}
}
}
})
</script>
效果图如下:
1.2 vm.$watch动态监视
不仅可以给属性
(即data
中定义的)添加监视,也可以给计算属性
添加监视。
下面例子,我们通过vm.$watch
方式,来动态给计算属性info
添加监视:
<div id="root">
<h2>今天我们去吃{{info}}</h2>
<button @click="change">切换</button>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
isHuoguo:true
},
computed:{
info() {
return this.isHuoguo?'火锅':'南京大排档';
}
},
methods: {
change() {
this.isHuoguo = !this.isHuoguo;
}
},
watch: {
isHuoguo:{
// immediate:true,//默认为false,初始化时,让handler调用一下。
handler(newValue, oldValue) {
console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
}
}
}
})
// 监视计算属性
vm.$watch('info',{
// immediate:true,//默认为false,初始化时,让handler调用一下。
handler(newValue, oldValue) {
console.log("info计算属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
}
})
</script>
1.3 深度监视(deep watch)
深度监视(deep watch
):
Vue
中的watch
默认不监测对象内部值的改变(只监测一层结构)- 配置
deep:true
可以监测对象内部值的改变(可以监测多层结构),Vue
默认不开启deep
,是为了提供效率。 Vue
自身可以监测对象内部值的改变,但是Vue
提供的watch
默认不可以。- 使用
watch
时,要根据数据的具体结构,决定是否采用深度监视。
使用方式:
- 监视多级结构中某个属性的变化,例如下面例子中
numbers.a
- 监视多级结构中所有属性的变化,
numbers:{deep:true,handler(){}}
<div id="root">
<h3>今天我们去吃{{info}}</h3>
<button @click="change">切换</button>
<hr>
<h3>a的值是{{numbers.a}}</h3>
<button @click="numbers.a++">点击a++</button>
<hr>
<h3>b的值是{{numbers.b}}</h3>
<button @click="numbers.b++">点击b++</button>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
isHuoguo:true,
numbers:{
a:1,
b:1
}
},
computed:{
info() {
return this.isHuoguo?'火锅':'南京大排档';
}
},
methods: {
change() {
this.isHuoguo = !this.isHuoguo;
}
},
watch: {
isHuoguo:{
handler(newValue, oldValue) {
console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
}
},
// 监视多级结构中某个属性的变化
"numbers.a": {
handler() {
console.log("a被改变了!");
}
},
// 监视多级结构中所有属性的变化
numbers:{
deep:true,
handler() {
console.log("numbers改变了!");
}
}
}
})
</script>
1.4 简写形式
当所配置的监视,只需要handler
,不需要其他配置的时候,才可以使用简写形式,使用函数来代替。
两类简写形式:
- watch配置里的简写
- 动态添加监视的简写
<div id="root">
<h3>今天我们去吃{{info}}</h3>
<button @click="change">切换</button>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
isHuoguo:true
},
computed:{
info() {
return this.isHuoguo?'火锅':'南京大排档';
}
},
methods: {
change() {
this.isHuoguo = !this.isHuoguo;
}
},
watch: {
/* isHuoguo:{
deep:true,
immediate:true,
handler(newValue, oldValue) {
console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
}
}, */
// 简写形式
isHuoguo(newValue, oldValue) {
console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
}
}
})
// 动态添加监视的简写
vm.$watch('isHuoguo',function(newValue, oldValue){
console.log("isHuoguo属性被修改了,newValue:"+newValue+",oldValue:"+oldValue);
})
</script>
二、computed和watch的对比
计算属性(computed
)和监视属性(watch
)之间的区别:
computed
能完成的功能,watch
都可以完成watch
能完成的功能,computed
不一定能完成,例如:watch
可以进行异步操作。
两个重要的原则
3. 被Vue
所管理的函数,最好写成普通函数,这样this
的指向才是vm
或组件实例对象
4. 所有不被Vue
管理的函数(定时器的回调函数(setTimeout
)、ajax
的回调函数、Promise
的回调函数等),最好写成箭头函数
,这样this
的指向才是 vm
或 组件实例对象
。
2.1 使用watch实现setTimeout操作
下面代码,使用了watch
实现setTimeout
操作,有一点需要注意的是,setTimeout
所指定的回调函数要使用箭头函数(因为箭头函数本身没有this
),否则this
指向window
了,而不再是vm
实例。
<div id="root">
<div class="row">姓:<input type="text" v-model="firstName"></div>
<div class="row">名:<input type="text" v-model="lastName"></div>
<div class="row">全名:<span>{{fullName}}</span></div>
</div>
<script>
const vm = new Vue({
el:'#root',
data() {
return {
firstName: '小',
lastName: '三',
fullName:'小-三'
};
},
methods:{
},
watch:{
firstName(val) {
setTimeout(() => { //这里不能写成普通函数,否则this指向window了
console.log(this); //vm实例对象
this.fullName = val + "-" + this.lastName;
}, 1000);
},
lastName(val){
this.fullName = this.firstName + "-" + val;
}
}
});
</script>
2.2 用computed无法实现setTimeout
用computed
计算属性,无法实现setTimeout
想要的功能,如下错误代码所示:
<div id="root">
<div class="row">姓:<input type="text" v-model="firstName"></div>
<div class="row">名:<input type="text" v-model="lastName"></div>
<div class="row">全名:<span>{{fullName}}</span></div>
</div>
<script>
const vm = new Vue({
el:'#root',
// 对于Vue来说,data中配置的就是属性。
// 计算属性:用现有的属性去加工、计算生成一个全新的属性。和属性分开放
data:{
firstName: '小',
lastName: '三'
},
computed:{
fullName() {
console.log('get被调用了!');
// console.log(this);
setTimeout(() => {
return this.firstName+'-'+this.lastName
}, 1000);
}
}
});
</script>
三、其他注意事项
3.1 vue devtools的bug
当页面上没有用到某个计算属性时,vue devtools
调试工具会出现一个bug
:不会显示数据的变化了。例如下面代码
<div id="root">
<h2>今天我们去吃米饭</h2>
<button @click="change">切换</button>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
isHuoguo:true
},
computed:{
info() {
return this.isHuoguo?'火锅':'南京大排档';
}
},
methods: {
change() {
this.isHuoguo = !this.isHuoguo;
}
},
})
</script>
点击切换按钮,工具中显示的data
和computed
不发生变化,其实数据已经发生了改变。可以通过控制台中输入vm.info
来查看。如下图所示:
3.2 @xxx=yyy格式
这里的yyy
不是事件名称,而是一些简单的语句。例如:@click="isHuoguo = !isHuoguo;count++;"
下面的案例中,两个按钮均可实现功能。不过需要注意的是,执行语句比较复杂的时候不建议直接写在yyy
中。
<div id="root">
<h2>今天我们去吃{{info}}--切换次数{{count}}</h2>
<button @click="change">切换</button>
<button @click="isHuoguo = !isHuoguo;count++">切换2</button>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
isHuoguo:true,
count:0,
},
computed:{
info() {
return this.isHuoguo?'火锅':'南京大排档';
}
},
methods: {
change() {
this.count++;
this.isHuoguo = !this.isHuoguo;
}
},
})
</script>
3.3 将window传入data中
将window
传入data
中,实现alert
弹框。如下代码所示:
<div id="root">
<h2>今天我们去吃{{info}}--切换次数{{count}}</h2>
<button @click="change">切换</button>
<button @click="isHuoguo = !isHuoguo;count++">切换2</button>
<button @click="window.alert(1)">弹出alert</button>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
isHuoguo:true,
count:0,
window //相当于window:window
},
computed:{
info() {
return this.isHuoguo?'火锅':'南京大排档';
}
},
methods: {
change() {
this.count++;
this.isHuoguo = !this.isHuoguo;
}
},
})
</script>