Vue3 监听属性
computed 帮我们"算出新值",而 watch(侦听器)帮我们"等待变化":当某个数据发生变化时去执行一段逻辑,比如重新请求接口、保存草稿、记录日志。凡是"数据变了要做点副作用"的场景,都可以交给 watch。
基本用法
watch 接收两个参数:要监听的数据源,以及变化时执行的回调。回调可以拿到新值和旧值:
<template>
<input v-model="keyword" placeholder="输入搜索词" />
</template>
<script setup>
import { ref, watch } from 'vue'
const keyword = ref('')
watch(keyword, (newVal, oldVal) => {
console.log(`搜索词从 "${oldVal}" 变成 "${newVal}"`)
})
</script>
效果:每输入一个字符控制台就打印一次,比如从 "" 变成 "v"、再变成 "vu"。
监听多个数据源
传入一个数组可以同时监听多个值,回调参数会按顺序对应展开:
<script setup>
import { ref, watch } from 'vue'
const width = ref(100)
const height = ref(200)
watch([width, height], ([w, h], [oldW, oldH]) => {
console.log(`尺寸变化:${oldW}x${oldH} -> ${w}x${h}`)
})
</script>
效果:width 或 height 任一变化都会触发回调,两个新值、两个旧值成对取出。
监听对象与 deep
watch 默认是"浅监听":只有整个对象被替换(引用变化)才触发。要监听对象内部属性的变化,需要开启 deep: true 深度监听:
<script setup>
import { ref, watch } from 'vue'
const user = ref({ name: '张三', age: 25 })
watch(user, (val) => {
console.log('user 变化了,当前年龄', val.age)
}, { deep: true })
user.value.age = 26
// 效果:只有加了 deep: true 才会打印"user 变化了,当前年龄 26"
</script>
注意 deep 会递归遍历对象,数据量大时有性能开销,能分别监听具体属性时尽量别整个对象深监听。
immediate 选项
默认 watch 要等数据第一次变化才执行回调。加上 immediate: true 后,回调会在初始化时立即执行一次,适合"组件一进来就按当前值请求数据"的场景:
watch(keyword, (val) => {
// 假设 fetchList 是封装好的接口请求方法
fetchList(val)
}, { immediate: true })
watch 与 computed 怎么选
一句话总结:computed 用于"依赖数据自动算出展示值",必须同步返回结果;watch 用于"数据变化后执行副作用",可以是异步操作。能用 computed 表达的需求优先写 computed,watch 留给"变化后要做事"的场景。
小结
watch 让应用能对数据变化做出反应:单源用 watch(源, 回调),多源传数组,深层变化加 deep,初始化就要执行加 immediate。它是实现搜索防抖、接口联动、表单校验等功能的基石。