computed
computed虽然写法上像个函数,但是实际上是计算属性。它会根据data数据的数据对象做计算处理,就类似于getter跟setter一样创造一个存取器属性。它有个特点,就是Vue内部做了缓存处理,只有它的依赖属性发生了变化,它才会重新计算并且触发渲染。否则不会再次触发计算。
写法
类型:{ [key: string]: Function | { get: Function, set: Function } }
普通写法
const vm=new Vue({
data:{
a:1
},
computed:{
b:function(){
return this.a+1
},
c(){ // es6写法
return this.a+2
}
}
})
vm.b //2
vm.c //3
上面的属性只有getter效果,我们只能够读取计算属性的值
存取器写法
const vm=new Vue({
data:{n:1},
computed:{
a:{
get(){return this.n+1},
set(value){this.n=value-1}
}
}
})
vm.n // 1
vm.a =3
vm.n //2
存取器的写法看上去就像设置一个属性一样了,而且我们还可以设置计算属性的值,上面的写法会影响到响应式属性n
,当设置vm.a
时,vm.n
也会发生变化。
computed默认有缓存效果,当计算属性没有发生变化时,不会重新计算更不会重新渲染。
watch
类型:{ [key: string]: string | Function | Object | Array }
watch翻译为观察,在vue中它是一个侦听器,会对依赖属性进行侦听(观察)。当侦听的属性发生变化时,就会执行一个函数。值得注意的是,watch是异步函数,如果我们的属性需要在侦听后再执行某个变化,可以使用
$nextTick
这个API
写法
let vm = new Vue({
data: {
a: 1,
b: {
c: 2
},
d: {
e: {
f: 3
}
},
},
watch: {
a(newvalue, oldValue) {
console.log( 'a变了')
},
b: {
handler: function (v, oldv) {
console.log("b变了")
},
immediate: true //在侦听开始时就调用回调函数
},
'b.c': function (v, oldv) {
console.log("b.c变了")
},
d: {
handler: function (v, oldv) {
console.log("d变了")
},
deep: true // 深侦听,只要d、d.e包括d.e.f发生变化都会侦听到
}
}
})
// vm.b 变了
vm.a=2 //a变了
vm.b={c:2} // b变了
vm.b={c:2,x:3} //b变了
vm.b={c:3} //b 变了 b.c变了
vm.b.c=100 //b.c变了
vm.d.e.f=4 //d变了
要了解watch,首先要知道属性发生变化的几种类型。
属性值的不同影响watch结果
-
当属性值为简单数据类型时,以
vm.a
为例,由于此时属性值是简单数据类型,所以很容易监听到其发生变化。此时属性值!==
改变后的属性值,就会触发watch -
当属性值为复杂数据类型时,以
vm.b
为例子,它保存了{c:2}
这个值。 如果它的内存地址发生变化,也就是说原先的{c:2}
和我后来设置的{c:2}
的内存地址不一致,所以就会触发b变了
,
结论
-
当监听属性的属性值为简单数据类型,就互相比较值,值不一样就触发
watch
-
如果监听的属性的属性值是复杂数据类型,就比较地址。地址不一样就触发
watch
deep 和 immediate
deep
表示深侦听,也就是我设置的属性对应的属性值即使是复杂数据类型,加上deep
,就全方位侦听,包括地址、内层属性的地址、内层属性的属性值。
immediate
是表示当侦听开始时就先触发callback
函数,默认为一开始不会触发watch
效果,而仅仅是侦听。
两者的应用场景
当我们试图通过数据对象来创造另一个属性时,推荐使用computed
当我们试图通过侦听数据对象的改变来做点什么(比如执行一个函数),我们就可以使用watch,在使用watch时尤其要注意其为异步执行的特点。