深入剖析侦听器
一、深入剖析侦听器
侦听属性,响应数据(data&computed)的变化,当数据变化时,会立刻执行对应函数。
1.值类型
1.函数类型
const vm = new Vue({
el: '#app',
data: {
msg: '天气真好!'
},
watch: {
msg(){
console.log('msg的值改变了!');
}
}
});
侦听器函数,会接收两个参数,第一个参数为newVal(被改变的数据),第二个参数为oldVal(赋值新值之前的值)。如在上述代码中,将侦听器watch更改一下,如:
const vm = new Vue({
el: '#app',
data: {
msg: '天气真好!'
},
watch: {
msg(newVal,oldVal){
console.log(newVal,'msg的值改变了!',oldVal);
}
}
});
2.字符串类型
值为方法名字,被侦听的数据改变时,会执行该方法。
const vm = new Vue({
el: '#app',
data: {
msg: '天气真好!'
},
methods: {
msgChange(){
console.log('msg的值改变了');
}
},
watch: {
msg: 'msgChange'
}
});
3.对象类型
写成对象类型时,可以提供选项。
1.handler
必需。handler是被侦听的数据改变时执行的回调函数。
handler的值类型为函数/字符串,写成字符串时为一个方法的名字。
const vm = new Vue({
el: '#app',
data: {
msg: '天气真好!',
eg: 'hellow!'
},
methods: {
egChange(){
console.log('eg的值改变了');
}
},
watch: {
msg: {
handler(){
console.log('msg的值改变了');
}
},
eg: {
handler: 'egChange'
}
}
});
2.deep
在默认情况下,侦听器侦听对象只侦听引用的变化,只有在给对象赋值时它才能被监听到。所以需要使用deep选项,让其可以发现对象内部值的变化,将deep的值设置为true,那么无论该对象被嵌套的有多深,都会被侦听到。
watch: {
person: {
handler(){
console.log('person的值改变了');
},
deep: true
}
}
注意,当对象的属性较多的时候,性能开销会比较大,此时可以监听对象的某个属性,这个后面再说。
3.immediate
加上immediate选项后,回调将会在侦听开始之后立刻被调用。而不是等待侦听的数据更改后才会调用。
methods: {
personChange(){
console.log('person的值改变了');
}
},
watch: {
person: {
handler: 'personChange',
immediate: true
}
}
4.数组类型
可以将多种不同值类型写在一个数组中。如:
methods: {
personChange(){
console.log('person的值改变了');
}
},
watch: {
person: [
'personChange',
{
handler: 'personChange',
immediate: true
}
]
}
2.键类型
1.正常对象key值
以上演示的都是正常的对象key值,这里不再赘述。
2.字符串类型key值
当key值类型为字符串时,可以实现监听对象当中的某一个属性,如:
data: {
person: {
name: 'jimo'
}
},
methods: {
personChange(){
console.log('person的值改变了');
}
},
watch: {
'person.name': {
handler: 'personChange'
}
}
3.vm.$watch
Vue实例将会在实例化时调用$watch
,遍历watch对象的每一个属性。
我们也可以利用vm.$watch
来实现侦听,用法与watch选项部分一致,略有不同。以下为使用方法。
1. 侦听某个数据的变化
- 三个参数,一参为被侦听的数据;二参为数据改变时执行的回调函数;三参可选,为设置的选项对象
vm.$watch(
'person',
function (){
console.log('person的值改变了')
},
{
deep: true
}
);
- 二个参数,一参为被侦听的数据;二参为选项对象,其中handler属性为必需,是数据改变时执行的回调函数,其他属性可选。
const vm = new Vue({
el: '#app',
data: {
person: {
name: 'jimo'
}
},
methods: {
personChange(){
console.log('person的值改变了');
}
}
});
vm.$watch(
'person',
{
handler: 'personChange',
deep: true
}
);
2.侦听某个对象属性的变化
vm.$watch('obj.name', /**参数和上面一致*/)
3.当监听的数据的在初始不确定,由多个数据得到时,此时可以将第一个参数写成函数类型
const vm = new Vue({
el: '#app',
data: {
msg: '天气真好!',
eg: 'hellow!'
},
methods: {
msgChange(){
console.log('msg的值改变了');
}
}
});
vm.$watch(
function(){
// 表达式`this.a + this.b`每次得出一个不同的结果时该函数都会被调用
// 这就像监听一个未被定义的计算属性
return this.eg+this.msg
},
{
handler: 'msgChange'
}
);
侦听器函数执行后,会返回一个取消侦听函数,用来停止触发回调:
const unwatch = vm.$watch(
'msg',
{
handler: 'msgChange'
}
);
unwatch();
使用unwatch时,需要注意的是,在带有immediate选项时,不能在第一次回调时取消侦听数据。
const unwatch = vm.$watch(
'person',
function(){
unwatch();
},{
immediate: true
}
);
如果仍然希望在回调内部用一个取消侦听的函数,那么可以先检查该函数的可用性:
var unwatch = vm.$watch(
'person',
function(){
this.personChange();
if(unwatch){
unwatch();
};
},{
deep: true
}
);
4.侦听器 vs 计算属性
-
两者都可以观察和响应Vue实例上的数据的变动。
-
watch擅长处理的场景是:一个数据影响多个数据。计算属性擅长处理的场景是:多个数据影响一个数据。
-
在侦听器中可以执行异步,但是在计算属性中不可以,例:
使用侦听器:
var vm = new Vue({
el: '#app',
data: {
question: '',
},
watch: {
question () {
setTimeout(() => {
alert(this.question);
}, 1000)
}
}
})