watch()
- 基本概念
watch()
用于监视响应式数据的变化,并在数据变化时执行相应的回调函数。- 可以监视单个响应式数据、多个响应式数据的组合,或者一个计算属性。
- 返回值
- 返回一个函数,调用这个函数可以停止监视。
- 特点
watch()
默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。watch()
可以监视单个数据、多个数据的组合或计算属性。- 通过深度监视选项,可以方便地监视对象的内部属性变化。
- 立即执行选项可以在特定情况下立即执行回调函数,提供更多的控制。
watch()的参数说明
watch()
函数接收3个参数:数据源、回调函数、选项对象(可选)。
- 第一个参数:数据源(被监视的数据)
ref()
定义的数据:基本类型的响应式变量、对象类型的响应式变量。reactive()
定义的数据:对象类型的响应式变量。- 一个返回响应式数据的函数,比如一个计算属性的
getter
函数。 - 一个包含上述内容的数组。
- 第二个参数:回调函数
- 当数据源发生变化时,会调用这个回调函数。
- 回调函数接收三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数
onInvalidate
。- 如果只监视一个数据源,那么新值和旧值分别对应数据源变化后的新值和变化前的旧值。
- 如果监视多个数据源,那么新值和旧值分别是一个包含新数据源值的数组和一个包含旧数据源值的数组。
onInvalidate
: 这是一个用于注册副作用清理的回调函数。这个回调函数可以在watch()
的回调函数内部调用,传入一个清理函数作为参数。这个清理函数会在下次watch()
回调执行之前被调用,以便清理上一次执行产生的副作用。
- 示例:
(newValue, oldValue) => { /* 处理变化的逻辑 */ }
或
(newValue, oldValue, onInvalidate) => { /* 处理变化的逻辑, 用于注册副作用清理的回调函数 */ }
- 第三个参数:选项对象(可选)
deep
:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器。- 布尔值,默认值为
false
。 - 如果设置为
true
,则会进行深度监视,即当监视的是一个对象时,对象的内部属性发生变化也会触发回调函数。
- 布尔值,默认值为
immediate
:侦听器创建时立即触发回调。第一次调用时旧值是undefined
。- 布尔值,默认值为
false
。 - 如果设置为
true
,则在创建watch()
时立即调用回调函数,此时旧值是undefined
,新值是当前值。
- 布尔值,默认值为
flush
:控制回调函数的执行时机。参考回调的刷新时机及 watchEffect()。- 默认值是
'pre'
,表示在 DOM 更新之前执行回调; 'post'
表示在 DOM 更新之后执行回调;'sync'
表示同步执行回调,即立即执行回调函数,并且在响应式数据变化时同步更新视图。
- 默认值是
onTrack / onTrigger
:调试侦听器的依赖。参考调试侦听器。onTrack
(用于调试):当响应式数据被读取并作为依赖被追踪时,这个函数会被调用。可以在这个函数中记录哪些数据被读取了,以便进行调试和分析依赖关系。onTrigger
(用于调试):当响应式数据发生变化并触发依赖时,这个函数会被调用。可以在这个函数中记录哪些数据发生了变化,以便进行调试和分析依赖关系。
once
:回调函数只会运行一次。侦听器将在回调函数首次运行后自动停止。- 布尔值,默认值为
false
。 - 如果设置为
true
,回调函数只会执行一次。侦听器将在回调函数首次运行后自动停止。
- 布尔值,默认值为
示例
监视ref()
定义的【基本类型】数据
语法: watch(变量名, (newValue, oldValue) => {})
监视时直接写变量名,其本质上监视的是.value
。
<template>
<div>
<div>count: {
{ count }}</div>
<button @click="addCount">点击 count+1</button>
</div>
</template>
<script setup lang="ts">
import {
ref, watch } from 'vue';
let count = ref(0)
const addCount = () => {
count.value++
}
// watch 监视的是 ref定义的数据:count
watch(count, (newValue, oldValue) => {
console.log(`count 从 ${
oldValue} 变为 ${
newValue}`);
})
</script>
使用watch()
监视count
这个响应式变量的变化。当count
的值发生变化时,回调函数会被执行,打印出旧值和新值。
监视ref()
定义的【对象类型】数据
语法: watch(变量名, (newValue, oldValue) => {})
监视时直接写变量名,监视的是对象的引用地址值,如果想监视对象的内部属性变化,要手动开启深度监视(deep: true
)。
- 如果修改的是
ref()
定义的对象中的属性,newValue
和oldValue
都是新值,因为它们是同一个对象(同一个引用地址)。 - 如果修改整个
ref()
定义的对象,newValue
是新值,oldValue
是旧值,因为不是同一个对象了。
示例:
<template>
<div>
<p>姓名: {
{ person.name }}</p>
<p>年龄: {
{ person.age }}</p>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改整个人</button>
</div>
</template>
<script setup lang="ts">
import {
ref, watch } from 'vue';
const person = ref({
name: '张三',
age: 18
});
const changeName = () => {
person.value.name += '哈'
}
const changeAge = () => {
person.value.age ++
}
const changePerson = () => {
person.value = {
name: '李四', age: 17 }
}
// changeName、changeAge修改person的内部属性,不会改变person的引用地址,不会触发 watch
// changePerson 对 person 重新赋值,改变了person的引用地址,触发watch
watch(person, (newValue, oldValue) => {
console.log('newValue: ', newValue)
console.log('oldValue: ', oldValue)
})
</script>
如果想要深度监视对象的内部属性变化,可以在watch()
第三个参数(选项对象)中设置deep: true
:
watch(person, (newValue, oldValue) => {
console.log('newValue: ', newValue)
console.log(