Vue 中 computed 和 watch 的区别
computed 和 watch 的使用场景、特性对比及实现方式
问题
Vue 中 computed 和 watch 看似都能实现对数据的监听,它们有什么区别?
解答
computed 计算属性
计算属性基于 data 或 props 中的数据计算得到一个新值,这个新值只会根据依赖值的变化而变化。
data: {
firstName: 'David',
lastName: 'Beckham'
},
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName
}
}
在模板中使用:
<p>姓名:{{ fullName }}</p>
注意:计算属性不能在 data 中定义,否则会报错。computed 属性如果是函数,默认走 get 方法,必须有返回值。
缓存特性:
computed: {
fullName: function () {
console.log('computed') // 多次调用只打印一次
return this.firstName + ' ' + this.lastName
}
}
computed 只在初始化或依赖数据变化时执行,结果会被缓存。重复调用时,只要依赖数据不变,直接返回缓存结果。
getter/setter:
computed: {
fullName: {
get() {
return this.firstName + ' ' + this.lastName
},
set(val) {
const names = val ? val.split(' ') : [];
this.firstName = names[0]
this.lastName = names[1]
}
}
}
watch 监听属性
watch 用于监听 Vue 实例上的属性变化,当属性变化时执行特定的业务逻辑。可以监听 data、props、computed 内的数据。
watch: {
firstName: function(val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function(val) {
this.fullName = this.firstName + ' ' + val
}
}
监听函数有两个参数:第一个是新值,第二个是旧值。
深度监听:
监听对象内部值的变化需要使用 deep 选项:
data: {
fullName: {
firstName: 'David',
lastName: 'Beckham'
}
},
watch: {
fullName: {
handler(newVal, oldVal) {
console.log(newVal);
console.log(oldVal);
},
deep: true
}
}
深度监听可以监听到对象的变化,但 newVal 和 oldVal 会指向同一个对象,无法区分具体哪个属性变化。
监听对象的单个属性:
方法一:直接监听属性
watch: {
'fullName.firstName': function(newVal, oldVal) {
console.log(newVal, oldVal);
}
}
方法二:配合 computed 使用
computed: {
firstNameChange() {
return this.fullName.firstName
}
},
watch: {
firstNameChange() {
console.log(this.fullName)
}
}
应用场景
computed 适用于:
- 处理复杂的逻辑运算
- 一个数据受一个或多个数据影响
- 处理模板中的复杂表达式
- 例如:购物车商品数量和总金额的关系
watch 适用于:
- 一个属性变化时需要执行特定业务逻辑
- 数据变化时执行异步或开销较大的操作
- 一个数据改变影响多个数据
- 例如:监控路由变化、input 输入框的特殊处理
关键点
- computed 有缓存机制,依赖数据不变时直接返回缓存结果;watch 不支持缓存,数据改变直接触发操作
- computed 必须有返回值,返回值作为新的计算属性;watch 不需要返回值,主要执行业务逻辑
- computed 不支持异步;watch 支持异步操作
- computed 适合多对一的场景(多个数据影响一个结果);watch 适合一对多的场景(一个数据变化影响多个操作)
- computed 基于依赖自动计算;watch 需要明确指定监听的数据源
目录