计算属性和监听属性
两者表面看起来都可以根据监听的值做出相应的行为的属性,那么究竟有什么优缺点,各自的最佳应用场景分别是什么呢
计算属性
- 计算属性的原理是通过监听依赖值得变化,从而动态返回内容,监听是一个过程,在监听到值变化时候,触发一个回调
- 数据可以进行逻辑处理,减少模板中计算逻辑(设计的主要目的)
- 对计算属性中的数据进行监视
- 依赖固定的数据类型(响应式数据)
计算属性的组成
- 通过get和set分别来获取计算属性和设置计算属性,默认只有get,需要set需要自己添加,也就是我们常写的计算属性中的那个回调函数,就是他的set,而且不是直接修改计算属性,而是修改他的依赖
例子1:
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
//this.fullName = newValue 这种写法会报错
var names = newValue.split(' ')
this.firstName = names[0]//对它的依赖进行赋值
this.lastName = names[names.length - 1]
}
}
}
小结:现在再运行fullName = 'i am other',setter被调用,然后firstName和lastName被更新,计算属性必须是一个函数,而且要有返回值
计算属性和方法的区别
- 两者最主要的区别:computed 是可以缓存的,methods 不能缓存;**只要相关依赖没有改变,多次访问计算属性得到的值是之前缓存的计算结果,不会多次执行。**网上有种说法就是方法可以传参,而计算属性不能,其实并不准确,计算属性可以通过闭包来实现传参
:data="closure(a, b, c)"
computed: {
closure () {
return function (a, b, c) {
/** do something */
return data
}
}
}
监听属性
- Vue提供了一种更通用得方式来观察和响应Vue实例上的数据变动:监听属性Watch,其中可以执行任何逻辑,例如:函数节流,ajax异步获取数据
例子1:我们先看一个demo
<template>
<div>
<el-input v-model="demo"></el-input>
{{value}}
</div>
</template>
<script>
export default {
name: 'index',
data() {
return {
demo: '',
value: ''
};
},
watch: {
demo(val) {
this.value = this.demo;
}
}
};
</script>
小结:watch来直接监听demo,如果demo的值变化,value的值也会一起变化
例子2:watch监听对象
<template>
<div>
<el-input v-model="demo.name"></el-input>
{{value}}
</div>
</template>
<script>
export default {
name: 'index',
data() {
return {
demo: {
name: ''
},
value: ''
};
},
computed: {
newName() {
return this.demo.name;
}
},
watch: {
newName(val) {
this.value = val;
}
}
};
</script>
小结:watch直接监听一个对象是不行的,所以先通过计算属性监听,然后watch监听计算属性
例子3:深度监听,deep
<div id="app">
<input type="text" v-model="childrens.name" />
<input type="text" v-model="lastName" />
</div>
<script type="text/javascript">
var vm = new Vue( {
el: '#app',
data: {
childrens: {
name: '小强',
age: 20,
sex: '男'
},
tdArray:["1","2"],
lastName:"张三"
},
watch:{
childrens:{
handler:function(val,oldval){
console.log(val.name)
},
deep:true//对象内部的属性监听,也叫深度监听
},
'childrens.name':function(val,oldval){
console.log(val+"aaa")
},//键路径必须加上引号
lastName:function(val,oldval){
console.log(this.lastName)
}
},//以V-model绑定数据时使用的数据变化监测
} );
vm.watch("lastName",function(val,oldval){
console.log(val)
})//主动调用watch方法来进行数据监测
</script>
<script type="text/javascript">
var vm = new Vue( {
el: '#app',
data: {
childrens: {
name: '小强',
age: 20,
sex: '男'
},
tdArray:["1","2"],
lastName:"张三"
},
watch:{
childrens:{
handler:function(val,oldval){
console.log(val.name)
},
deep:true//对象内部的属性监听,也叫深度监听
},
'childrens.name':function(val,oldval){
console.log(val+"aaa")
},//键路径必须加上引号
lastName:function(val,oldval){
console.log(this.lastName)
}
},//以V-model绑定数据时使用的数据变化监测
} );
vm.watch方法来进行数据监测
</script>
小结:对象内部的属性监听需要深度监听,键路径必须加引号,数组的变化不需要深度watch
例子4:这个例子大家可以跑一下,涵盖了大部分情况
<template>
<div class="attr">
<h1>watch属性</h1>
<h2>{{ $data }}</h2>
<button @click="() => (a += 1)">修改a的值</button>
</div>
</template>
<script>
export default {
data() {
return {
a: 1,
b: { c: 2, d: 3 },
e: {
f: {
g: 4
}
},
h: []
};
},
watch: {
a: function(val, oldVal) {
this.b.c += 1;
},
"b.c": function(val, oldVal) {
this.b.d += 1;
},
"b.d": function(val, oldVal) {
this.e.f.g += 1;
},
e: {
handler: function(val, oldVal) {
this.h.push("浪里行舟");
},
deep: true //用于监听e对象内部值的变化
}
}
};
</script>
小结:当点击按钮,a的值加一,然后触发a的监听,b.c加一,然后触发b.c以此触发下去,这里可以注意到,使用对象里的属性时候键路径必须加引号。
区别
watch:监测的是属性值, 只要属性值发生变化,其都会触发执行回调函数来执行一系列操作。
computed:监测的是依赖值,依赖值不变的情况下其会直接读取缓存进行复用,变化的情况下才会重新计算。
「计算属性不能执行异步任务,计算属性必须同步执行」。也就是说计算属性不能向服务器请求或者执行异步任务。如果遇到异步任务,就交给侦听属性。watch也可以检测computed属性。
总结
计算属性适合用在模板渲染中,某个值是依赖了其它的响应式对象甚至是计算属性计算而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。
- computed能做的,watch都能做,反之则不行
- 能用computed的尽量用computed