Vue2极简教程010-对比computed和watch
Vue2极简教程010:computed vs watch 深度对比指南
一、核心概念对比
特性 | computed | watch |
---|---|---|
本质 | 计算属性 | 监听器 |
触发时机 | 依赖数据变化时自动计算 | 指定数据变化时执行回调 |
返回值 | 必须返回结果 | 无返回值 |
异步支持 | 不支持 | 支持 |
缓存机制 | 有缓存(依赖不变不重新计算) | 无缓存(每次变化都执行) |
适用场景 | 模板中使用的派生数据 | 数据变化时需要执行副作用操作 |
二、语法结构对比
1. computed 基础用法
computed: {
// 简写形式(仅getter)
fullName() {
return this.firstName + ' ' + this.lastName
},
// 完整形式(getter/setter)
reversedMessage: {
get() {
return this.message.split('').reverse().join('')
},
set(newVal) {
this.message = newVal.split('').reverse().join('')
}
}
}
2. watch 基础用法
watch: {
// 基本监听
firstName(newVal, oldVal) {
console.log(`名字从 ${oldVal} 变为 ${newVal}`)
},
// 深度监听对象
user: {
handler(newVal) {
console.log('用户信息变化', newVal)
},
deep: true, // 深度监听
immediate: true // 立即执行
},
// 监听特定属性
'obj.property'(newVal) {
// 处理变化
}
}
三、工作原理解析
computed 实现机制
graph LR
A[响应式依赖] --> B(computed计算)
B --> C{依赖是否变化?}
C -->|否| D[返回缓存值]
C -->|是| E[重新计算并缓存]
watch 实现机制
graph LR
A[监听目标] --> B{值是否变化?}
B -->|是| C[执行回调函数]
B -->|否| D[不执行任何操作]
四、经典场景对比
适用 computed 的场景
表单验证状态
computed: { isFormValid() { return this.username.length > 0 && this.password.length >= 6 && this.agreeTerms } }
过滤列表数据
computed: { filteredList() { return this.items.filter(item => item.name.includes(this.searchText) ) } }
适用 watch 的场景
异步数据获取
watch: { searchText(newVal) { clearTimeout(this.timer) this.timer = setTimeout(() => { this.fetchResults(newVal) }, 500) } }
路由参数变化
watch: { '$route.params.id'(newId) { this.loadUserData(newId) } }
五、性能优化建议
computed 最佳实践
- 避免在计算属性中做复杂计算(超过1ms应考虑缓存)
不要修改依赖数据(应使用setter)
// 反模式 computed: { badExample() { this.someData = process(this.otherData) // 错误! return this.someData } }
watch 最佳实践
- 对集合类型数据使用
deep: true
要谨慎 大量数据监听时使用
immediate: false
watch: { bigData: { handler() { /* 处理 */ }, deep: true, immediate: false // 避免初始化执行 } }
- 对集合类型数据使用
六、特殊用法技巧
1. computed 的依赖追踪
// 只会追踪this.a和this.b的变化
computed: {
example() {
return this.a + this.b + window.externalVar // 不追踪window.externalVar
}
}
2. watch 的强制触发
this.$watch(
'someData',
() => { /* 处理 */ },
{ flush: 'post' } // DOM更新后触发
)
七、企业级应用示例
购物车总价计算(computed)
computed: {
totalPrice() {
return this.cartItems.reduce((sum, item) => {
return sum + (item.price * item.quantity)
}, 0)
},
discountPrice() {
return this.totalPrice * (1 - this.discountRate)
}
}
用户权限变更处理(watch)
watch: {
userRole(newRole) {
this.resetUI()
this.fetchMenu(newRole)
this.checkLicense(newRole)
// 路由跳转
if (newRole === 'guest') {
this.$router.push('/login')
}
}
}
八、选择决策流程图
graph TD
A[需要响应数据变化?] --> B{需要新值吗?}
B -->|是| C{是否依赖多个数据源?}
C -->|是| D[使用 computed]
C -->|否| E{需要异步操作吗?}
E -->|是| F[使用 watch]
E -->|否| D
B -->|否| G{需要执行副作用吗?}
G -->|是| F
G -->|否| H[可能都不需要]
黄金法则:
- 当需要基于现有数据计算新数据时 → computed
- 当需要在数据变化时执行操作时 → watch
- 涉及异步操作或昂贵操作时 → watch + 防抖
- 模板中使用的派生数据 → 必须用computed