vue3 watch(保姆级教程)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

在 Vue.js 的开发过程中,响应式系统是其核心特性之一。无论是数据驱动视图更新,还是通过事件监听实现状态同步,开发者都希望代码能够直观、高效地响应用户行为或数据变化。在 Vue3 中,watch 是实现这一目标的关键工具之一。它不仅能够监听单个响应式数据的变化,还能处理复杂对象、数组的深层变化,甚至支持异步操作和防抖节流等高级场景。

本文将从基础用法到进阶技巧,结合实际案例,深入解析 Vue3 中 watch 的核心功能与最佳实践。无论你是刚接触 Vue 的新手,还是有一定经验的开发者,都能从中找到适合自己的知识内容。


一、Vue3 watch 的基本概念与核心作用

1.1 什么是 watch

watch 是 Vue3 提供的用于监听响应式数据变化的 API。它类似于一个“传感器”,当被监听的数据发生变更时,会自动触发预设的回调函数,从而执行相应的逻辑操作。

形象比喻
可以把 watch 想象成一个保安系统。当你设置一个 watch 监听某个数据时,就像在数据的“门口”安装了一个摄像头,一旦数据被修改,摄像头就会立即通知保安(即 watch 的回调函数),并触发预设的响应动作(比如记录日志、更新视图等)。

1.2 watch 的核心作用

  • 响应式数据变化:监听单个或多个响应式变量的变化。
  • 执行副作用逻辑:在数据变化后,自动执行特定操作(如发送网络请求、更新 UI 状态)。
  • 处理复杂依赖:支持监听嵌套对象、数组的深层变化。
  • 优化性能:通过配置选项(如 deepimmediate)控制监听行为,避免不必要的重复计算。

二、watch 的基础用法与代码示例

2.1 监听单个响应式数据

示例:监听用户输入的姓名

<script setup>
import { ref, watch } from 'vue'

const name = ref('')
const message = ref('等待输入...')

// 监听 `name` 的变化
watch(name, (newVal, oldVal) => {
  if (newVal === 'Vue') {
    message.value = '欢迎 Vue 之友!'
  } else {
    message.value = `当前输入:${newVal}`
  }
})
</script>

<template>
  <input v-model="name" placeholder="输入你的名字">
  <p>{{ message }}</p>
</template>

解析

  • 当用户输入内容时,name 的值会被更新。
  • watch 回调函数会接收到新值 newVal 和旧值 oldVal,根据新值修改 message 的内容。

2.2 监听多个响应式数据

示例:计算购物车总价

<script setup>
import { ref, watch } from 'vue'

const price = ref(0)
const quantity = ref(1)
const total = ref(0)

// 同时监听 `price` 和 `quantity`
watch([price, quantity], ([newPrice, newQuantity], [oldPrice, oldQuantity]) => {
  total.value = newPrice * newQuantity
  console.log(`总价从 ${oldPrice * oldQuantity} 变为 ${total.value}`)
})
</script>

<template>
  <input v-model="price" type="number" placeholder="单价">
  <input v-model="quantity" type="number" placeholder="数量">
  <p>总价:{{ total }}</p>
</template>

关键点

  • 当监听多个数据时,需要将它们包装成数组传递给 watch
  • 回调函数的参数会以数组形式返回新值和旧值,需按顺序解构。

2.3 监听嵌套对象或数组的深层变化

默认情况下,watch 只能监听顶层属性的变化。若需要监听对象内部属性或数组元素的变化,需通过 deep 配置项开启深度监听。

示例:监听购物车商品列表

<script setup>
import { ref, watch } from 'vue'

const cart = ref([
  { id: 1, name: '笔记本', price: 1000 },
  { id: 2, name: 'U盘', price: 50 }
])

// 开启深度监听
watch(cart, (newCart, oldCart) => {
  console.log('购物车内容发生变化')
}, { deep: true })
</script>

<template>
  <button @click="cart.value[0].price += 100">
    提升第一件商品的价格
  </button>
</template>

注意

  • 使用 deep: true 可能导致性能损耗,需谨慎使用。
  • 对于大型对象,建议直接监听具体属性,而非整个对象。

三、watch 的高级用法与配置选项

3.1 immediate:立即执行回调

通过 immediate 配置项,可以让 watch初始绑定时立即执行一次回调,常用于初始化操作。

示例:页面加载时执行数据校验

<script setup>
import { ref, watch } from 'vue'

const form = ref({ username: '' })

// 监听表单内容,同时立即执行校验
watch(
  () => form.value.username,
  (newVal) => {
    console.log('校验用户名:', newVal)
  },
  { immediate: true }
)
</script>

3.2 flush:控制回调执行时机

flush 配置项可以指定回调函数的执行时机,支持以下三个选项:

  • 'pre':在 DOM 更新前执行(默认值)。
  • 'post':在 DOM 更新后执行。
  • 'sync':同步执行,不等待微任务队列。

示例:在 DOM 更新后执行副作用

<script setup>
import { ref, watch } from 'vue'

const count = ref(0)

// 在 DOM 更新后获取元素高度
watch(count, (newVal) => {
  console.log('当前 count:', newVal)
  console.log('DOM 高度:', document.body.offsetHeight)
}, { flush: 'post' })
</script>

3.3 结合 watch 处理异步操作

watch 的回调函数中,可以直接执行异步操作(如 API 请求),但需注意以下两点:

  1. 使用 async/awaitPromise 显式声明异步函数。
  2. 避免在回调中直接修改被监听的响应式数据,否则可能导致循环依赖。

示例:输入框防抖搜索

<script setup>
import { ref, watch } from 'vue'

const searchQuery = ref('')
const searchResults = ref([])

// 防抖实现:使用 setTimeout + 清除前一个定时器
let timeoutId = null

watch(searchQuery, async (newQuery) => {
  clearTimeout(timeoutId)
  timeoutId = setTimeout(async () => {
    // 模拟 API 请求
    const response = await fetch(`https://api.example.com/search?q=${newQuery}`)
    searchResults.value = await response.json()
  }, 300) // 300ms 防抖延迟
})
</script>

四、watch 的最佳实践与注意事项

4.1 避免直接在回调中修改被监听的值

修改被监听的响应式数据会导致 watch 回调无限循环。例如:

watch(counter, (newVal) => {
  counter.value++ // ❌ 导致无限递归
})

解决方案

  • 通过其他响应式变量触发逻辑,或使用 watchEffect 替代。

4.2 使用 watchEffect 替代简单监听场景

如果需要监听多个响应式变量的组合变化,且无需控制执行时机或旧值,可以改用 watchEffect,它会自动追踪依赖并响应变化。

示例:自动计算商品总价

<script setup>
import { ref, watchEffect } from 'vue'

const price = ref(0)
const quantity = ref(1)
const total = ref(0)

watchEffect(() => {
  total.value = price.value * quantity.value
})
</script>

4.3 性能优化建议

  • 避免不必要的深度监听:优先监听具体属性,而非整个对象。
  • 使用 immediate 时谨慎初始化逻辑:确保初始值合理,避免无效操作。
  • 结合 async 和防抖/节流:减少高频数据变化对性能的影响。

五、实战案例:表单验证与实时提交

5.1 场景描述

假设需要实现一个表单,要求:

  1. 当用户输入内容时,实时显示输入长度。
  2. 当所有字段填写完成后,自动提交表单。

5.2 代码实现

<script setup>
import { ref, watch } from 'vue'

const form = ref({
  username: '',
  email: '',
  password: ''
})
const formValid = ref(false)

// 监听表单内容变化
watch(
  () => form.value,
  (newForm) => {
    // 计算表单有效性
    formValid.value = 
      newForm.username.trim() !== '' &&
      newForm.email.includes('@') &&
      newForm.password.length >= 6

    // 当表单有效时提交
    if (formValid.value) {
      console.log('自动提交:', newForm)
    }
  },
  { deep: true }
)
</script>

<template>
  <div>
    <input v-model="form.username" placeholder="用户名">
    <input v-model="form.email" placeholder="邮箱">
    <input v-model="form.password" type="password" placeholder="密码">
    <p>表单状态:{{ formValid ? '有效' : '无效' }}</p>
  </div>
</template>

六、结论

Vue3 的 watch 是一个功能强大且灵活的工具,它帮助开发者轻松实现响应式数据的监听与逻辑处理。通过掌握其基础语法、配置选项以及最佳实践,可以显著提升代码的可维护性和性能。

无论是简单的数据绑定,还是复杂的异步操作,watch 都能提供直观的解决方案。希望本文的案例与解析能为你在实际开发中提供参考,让你更自信地使用 vue3 watch 实现高效、优雅的代码逻辑。


关键词布局

  • 标题与小标题中自然包含“vue3 watch”
  • 正文通过代码示例和场景描述多次提及功能特性
  • 结论部分总结其核心价值,强化关键词记忆

最新发布