watch详解:与computed 对比以及 Vue2 / Vue3 区别

在 Vue 里,computedwatch 经常被放在一起比较。

很多人刚开始学的时候会有一个疑问:

两者都能监听数据变化,那到底什么时候用 computed,什么时候用 watch?

这篇文章直接从实战角度说清楚:

  • watch 是干什么的
  • watchcomputed 的核心区别
  • watch 适合哪些业务场景
  • Vue2 和 Vue3 里 watch 的写法有什么不同
  • 实战中怎么选

一、先说结论

一句话先记住:

  • computed 适合做派生值
  • watch 适合做响应副作用

什么叫副作用?

比如:

  • 数据变了,发请求
  • 某个字段变了,联动重置另一个字段
  • 路由参数变了,重新加载列表
  • 搜索条件变了,触发查询
  • 一个开关变化后,执行某些业务逻辑

这些都更像 watch 的工作。


二、watch 是什么

watch 是 Vue 提供的侦听器,它会监听某个响应式数据的变化,并在变化时执行回调。

比如:

js 复制代码
watch: {
  keyword(newVal, oldVal) {
    console.log('keyword变了', newVal, oldVal)
  }
}

只要 keyword 改变,就会触发这个函数。


三、watch 的核心特点

1. 它关注"变化"

watch 的核心不是"返回一个值",而是"监听变化后做事"。

2. 它适合副作用

比如请求接口、写入缓存、联动修改其他值、控制状态等。

3. 它可以拿到新值和旧值

这是 watch 很实用的一点:

js 复制代码
watch: {
  status(newVal, oldVal) {
    console.log(newVal, oldVal)
  }
}

你可以很方便地做前后值对比。

4. 它支持深度监听、立即执行

这些都是 computed 没有的典型能力。


四、watch 和 computed 的区别

1. computed 是"算结果",watch 是"做动作"

computed:

js 复制代码
computed: {
  fullName() {
    return this.firstName + ' ' + this.lastName
  }
}

它输出一个新值。

watch:

js 复制代码
watch: {
  fullName(newVal) {
    console.log('名字变了,做点事')
  }
}

它不负责返回结果,而是负责执行逻辑。


2. computed 有缓存,watch 没有缓存概念

computed 会缓存结果,依赖不变就不重新计算。

watch 不一样,它是只要侦听值变化,就触发回调


3. computed 适合模板展示,watch 适合业务联动

比如:

  • 页面上要显示"是否可编辑" -> computed
  • 选中某项后自动拉接口 -> watch

4. computed 更像"属性",watch 更像"事件"

computed 你会像用字段一样用它。

watch 更像是"这个值一变,就触发一个动作"。


五、watch 的典型使用场景

场景 1:搜索框输入后触发查询

js 复制代码
watch: {
  keyword(newVal) {
    this.pageNum = 1
    this.getList()
  }
}

当关键词变化时,自动查询列表。


场景 2:联动重置表单

js 复制代码
watch: {
  areaCode(newVal) {
    this.formData.streetCode = ''
  }
}

当区县变化时,重置街道。

这种联动在后台管理系统里特别常见。


场景 3:路由变化后重新加载数据

js 复制代码
watch: {
  '$route.query.id'(newVal) {
    this.getDetail(newVal)
  }
}

路由参数一变,重新请求详情。


场景 4:监听对象内部字段变化

js 复制代码
watch: {
  formData: {
    handler(newVal) {
      console.log('表单变了')
    },
    deep: true
  }
}

如果是对象或数组内部变化,常常需要 deep: true


六、watch 的常见写法


1. Vue2 选项式写法

这是最经典的写法:

js 复制代码
export default {
  data() {
    return {
      keyword: ''
    }
  },
  watch: {
    keyword(newVal, oldVal) {
      console.log(newVal, oldVal)
    }
  }
}

2. 对象形式写法

适合复杂监听:

js 复制代码
watch: {
  keyword: {
    handler(newVal, oldVal) {
      console.log(newVal, oldVal)
    },
    deep: true,
    immediate: true
  }
}

3. 深度监听

js 复制代码
watch: {
  formData: {
    handler(newVal) {
      console.log('formData changed')
    },
    deep: true
  }
}

适合监听对象内部属性变化。


4. 立即执行

js 复制代码
watch: {
  keyword: {
    handler(newVal) {
      this.getList()
    },
    immediate: true
  }
}

immediate: true 会让监听器在初始化时也执行一次。


七、Vue2 里的 watch

Vue2 中,watch 基本写在组件的 watch 选项里。

基础写法

js 复制代码
watch: {
  count(newVal) {
    console.log(newVal)
  }
}

带 immediate

js 复制代码
watch: {
  count: {
    handler(newVal) {
      console.log(newVal)
    },
    immediate: true
  }
}

带 deep

js 复制代码
watch: {
  obj: {
    handler() {
      console.log('obj changed')
    },
    deep: true
  }
}

监听路径

js 复制代码
watch: {
  'formData.areaCode'(newVal) {
    console.log(newVal)
  }
}

Vue2 的 watch 很适合传统后台项目,尤其是表单联动比较多的场景。


八、Vue3 里的 watch

Vue3 里,watch 主要和 refreactive 一起用,在组合式 API 中更灵活。

1. 监听 ref

js 复制代码
import { ref, watch } from 'vue'

const keyword = ref('')

watch(keyword, (newVal, oldVal) => {
  console.log(newVal, oldVal)
})

注意:

  • 监听的是 ref 本身
  • 不需要写 .value 当作监听源

2. 监听多个数据

js 复制代码
watch([keyword, pageNum], ([newKeyword, newPage]) => {
  console.log(newKeyword, newPage)
})

这个在查询条件联动时非常实用。


3. 监听 reactive 对象

js 复制代码
import { reactive, watch } from 'vue'

const formData = reactive({
  areaCode: '',
  streetCode: ''
})

watch(
  () => formData.areaCode,
  (newVal, oldVal) => {
    console.log(newVal, oldVal)
  }
)

Vue3 中监听 reactive 的属性,通常用 getter 函数写法更稳。


4. 深度监听

Vue3 中对 reactive 对象的监听,本身就更贴近响应式系统,但如果你要监听对象内部整体变化,仍然可能用到 deep: true

js 复制代码
watch(
  formData,
  () => {
    console.log('formData changed')
  },
  { deep: true }
)

5. 立即执行

js 复制代码
watch(
  keyword,
  (newVal) => {
    console.log(newVal)
  },
  { immediate: true }
)

这个和 Vue2 的 immediate 很类似。


九、Vue2 和 Vue3 的 watch 对比

1. 写法不同

Vue2:

js 复制代码
watch: {
  keyword(newVal) {
    console.log(newVal)
  }
}

Vue3:

js 复制代码
watch(keyword, (newVal) => {
  console.log(newVal)
})

2. 响应式来源不同

Vue2 多用 data,通过 this.xxx 访问。

Vue3 常用:

  • ref
  • reactive
  • computed

所以 Vue3 的 watch 更偏函数式写法。


3. 组合能力更强

Vue3 可以很自然地监听多个源:

js 复制代码
watch([keyword, pageNum], ([k, p]) => {
  console.log(k, p)
})

这在复杂业务里比 Vue2 更灵活。


4. 逻辑更容易拆分

Vue3 里 watch 可以和业务状态放在一起写,更适合组合式组织。


十、watch 的实战写法建议

建议 1:不要滥用 deep

deep: true 很方便,但也更耗性能。

如果只关心某个字段,尽量监听单个字段,不要整对象深度监听。

坏例子:

js 复制代码
watch: {
  formData: {
    handler() {},
    deep: true
  }
}

如果只是监听 areaCode,那就直接监听它。


建议 2:能监听具体字段就不要监听整个对象

比如:

js 复制代码
watch: {
  'formData.areaCode'(newVal) {
    this.formData.streetCode = ''
  }
}

比深度监听整个表单更清晰。


建议 3:watch 里尽量只做"响应动作"

比如:

  • 请求接口
  • 重置字段
  • 切换状态
  • 派发事件

不要在 watch 里塞太多复杂计算,复杂派生值尽量交给 computed。


建议 4:初始化时要分清要不要 immediate

有些场景你希望页面一加载就执行一次,比如:

  • 首次查询
  • 初始化联动数据

这时用 immediate: true 很合适。

但如果你不想初始就触发,记得不要加。


十一、一个典型的后台实战例子

比如数据分析页面:

  • 选择区县后,街道要重置
  • 选择年份后,自动刷新列表
  • 选择角色后,显示字段要变化

可以这么做:

js 复制代码
watch: {
  'formData.areaCode'(newVal) {
    this.formData.streetCode = ''
  },
  'formData.year'() {
    this.getList()
  }
}

这里用 watch 就非常自然:

  • 区县变了,联动清街道
  • 年份变了,重新查数据

而像"当前是否显示某列"这种派生判断,更适合 computed。


十二、watch 和 computed 怎么选

选 computed,如果:

  • 你要的是一个"计算结果"
  • 结果会被模板多次使用
  • 结果可以缓存
  • 没有副作用

例如:

  • fullName
  • showColumn
  • currentAreaCode
  • tableTitle

选 watch,如果:

  • 你要监听变化后做事
  • 需要发请求
  • 需要联动修改其他状态
  • 需要拿到新旧值

例如:

  • 搜索条件变化自动查询
  • 区县变化清空街道
  • 路由变化重新拉数据
  • 开关变化后执行某逻辑

十三、最后总结

watch 的本质不是"计算",而是"响应变化"。

它和 computed 的分工很明确:

  • computed 负责派生值
  • watch 负责副作用处理

你可以这样记:

  • 要展示结果,用 computed
  • 要监听变化做事,用 watch

Vue2 / Vue3 的区别也很清楚:

  • Vue2 更偏选项式写法
  • Vue3 更偏组合式写法
  • Vue3 的 watch 更灵活,适合复杂业务拆分
相关推荐
饭小猿人2 小时前
Flutter实现底部动画弹窗有两种方式
开发语言·前端·flutter
让学习成为一种生活方式2 小时前
pbtk v 3.5.0安装与使用--生信工具084
前端·chrome
heimeiyingwang2 小时前
【架构实战】FinOps云成本优化实践
前端·chrome·架构
2601_949814692 小时前
Docker部署Spring Boot + Vue项目
vue.js·spring boot·docker
Mr Xu_2 小时前
从后端数据到前端图表:深入解析 reduce 与 flatMap 的数据整形实战
前端·javascript
玖玖passion3 小时前
Windows 上部署 Hermes Agent 完整指南 - 让你的 AI 助手在 WSL2 中跑起来
前端·后端·github
AC赳赳老秦4 小时前
OpenClaw多平台部署:Windows+Linux跨系统协同,实现全场景覆盖
linux·服务器·前端·网络·windows·deepseek·openclaw
喜欢吃鱿鱼4 小时前
DES加解密(附带解决转义问题)-VUE
开发语言·前端·javascript