# Computed 和 Watch
Computed本质是一个具备缓存的watcher
,依赖的属性发生变化就会更新视图。
适用于计算比较消耗性能的计算场景。当表达式过于复杂时,在模板中放入过多逻辑会让模板难以维护,可以将复杂的逻辑放入计算属性中处理。
Watch没有缓存性,更多的是观察的作用,可以监听某些数据执行回调。当我们需要深度监听对象中的属性时,可以打开deep:true
选项,这样便会对对象中的每一项进行监听。这样会带来性能问题,优化的话可以使用字符串形式监听,如果没有写到组件中,不要忘记使用unWatch
手动注销哦。
- 功能上:
computed
是计算属性,也就是依赖其它的属性计算所得出最后的值。watch
是去监听一个值的变化,然后执行相对应的函数 - 使用上:
computed
中的函数必须要用return
返回;watch
的回调里面会传入监听属性的新旧值,通过这两个值可以做一些特定的操作,不是必须要用return
- 性能上:
computed
中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch
在每次监听的值发生变化的时候都会执行回调 - 场景上
- computed:当一个属性受多个属性影响的时候,例子:购物车商品结算;
- watch:当一条数据影响多条数据的时候,例子:搜索框
# 使用场景
computed和watch都起到监听/依赖一个数据,并进行处理的作用
computed
: 一个数据受多个数据影响,对同步数据的处理。
watch
: 一个数据影响多个数据,观测某个值的变化去完成一段开销较大的复杂业务逻辑。
# computed
很多时候, 在页面调用接口加载数据之前, 可能会出现报错的情况, 但是页面不会有问题, 那么产生这个问题的原因, 是什么呢?
例如下面的代码, 属性值不存在, 所以就报错了
<div>{{list.a.b}}</div>
<script>
var vm = new Vue({
el: '#demo',
data: {
list: {}
}
})
</script>
为了避免不报错, 这时候, 类似加个判断, 在数据多的情况下, 明显的优势就出来了
<div>{{b}}</div>
<script>
var vm = new Vue({
el: '#demo',
data: {
list: {}
},
computed: {
b(){
if(!Object.value(this.list).length && this.list.a.b){
return this.list.a.b
}else{
return ''
}
}
}
})
</script>
# watch的高级用法
- handler方法和immediate属性
<div id="demo">{{ fullName }}</div>
<script>
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
console.log('第一次没有执行~')
this.fullName = val + ' ' + this.lastName
}
}
})
</script>
可以看到,初始化的时候watch
是不会执行的。看上边的例子,只要当firstName
的值改变的时候才会执行监听计算。但如果想在第一次它在被绑定的时候就执行怎么办?
这时候就要修改一下我们的例子:
var vm = new Vue({
watch: {
firstName: {
handler(val) {
console.log('第一次执行了~')
this.fullName = val + ' ' + this.lastName
},
// 代表在watch里声明了firstName这个方法之后立即先去执行handler方法
immediate: true
}
}
})
- deep属性
watch
里还有一个deep
属性,代表是否开启深度监听,默认为false
,下面来看一个例子:
<div id="app">
<div>obj.a: {{obj.a}}</div>
<input type="text" v-model="obj.a">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
obj: {
a: 1
}
},
watch: {
obj: {
handler(val) {
console.log('obj.a changed')
},
immediate: true
}
}
})
</script>
当我们在input输入框中输入数据改变obj.a
的值时,我们发现在控制台没有打印出'obj.a changed'
。
受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。
由于 Vue 会在初始化实例时对属性执行getter/setter
转化过程,所以属性必须在data
对象上存在才能让 Vue 转换它,才能让它是响应式的。
所以,想要深度监听属性值的变化,就需要deep:true
了
watch: {
obj: {
handler(val) {
console.log('obj.a changed')
},
immediate: true,
deep: true
}
}
deep
属性的意思是深度遍历,会在对象一层层往下遍历,在每一层都加上监听器。
但是使用deep
属性会给每一层都加上监听器,性能开销可能就会非常大了。这样我们可以用字符串的形式来优化:
watch: {
'obj.a': {
handler(val) {
console.log('obj.a changed')
},
immediate: true
// deep: true
}
}
直到遇到'obj.a'
属性,才会给该属性设置监听函数,提高性能。