在有些情况下,我们需要在状态变化时执行一些“副作用”:例如更改 DOM ,或是根据异步操作的结果去修改另一处的状态。在组合式 API 中,我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数。
watch 函数可以侦听被 ref 和 reactive 包裹的数据。
watch 函数包含三个参数:
- 参数一: sources 被侦听的数据源;
- 参数二: cb callback 回调函数,函数中包含两个参数分别为新值和旧值;
- 参数三: options 侦听器的配置项, deep 、 immediate 等参数。
1. watch 的常规写法
<template><div>姓名:<input type="text" v-model="name" /></div>
</template><script setup lang="ts">
import { ref, reactive, watch } from 'vue'
const name = ref<string>('张三')
watch(name, (newVal: any, oldVal: any) => {console.log(newVal, oldVal)
})
</script>
当输入框中值发生变化时,侦听器会监听并在控制台打印出来:
2. watch侦听多个数据
watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组,侦听多个数据时:
<template><div>姓名:<input type="text" v-model="name" /></div><div>年龄:<input type="number" v-model="age" /></div>
</template><script setup lang="ts">import { ref, reactive, watch } from 'vue'const name = ref<string>('张三')const age = ref<number>(20)watch([name, age], (newVal: any, oldVal: any) => {console.log(newVal, oldVal)})
</script>
当被侦听的数据发生改变时:
3. watch侦听对象
(1)侦听使用 ref 的对象时,需要在侦听器的配置项中配置 deep 为 true :
<template><div>年龄:<input type="text" v-model="obj.foo.bar.name" /></div>
</template><script setup lang="ts">
import { ref, reactive, watch } from 'vue'
const obj = ref({foo: {bar: {name: '张三'}}
})
watch(obj,(newVal: any, oldVal: any) => {console.log(newVal, oldVal)},{deep: true // 深度监听}
)
</script>
由于对象是引用类型,新值和旧值指向同一内存地址,所以值一样。
(2)侦听使用 reactive 的对象时,不需要设置侦听器的配置项 deep :
<template><div>年龄:<input type="text" v-model="obj.foo.bar.name" /></div>
</template><script setup lang="ts">
import { ref, reactive, watch } from 'vue'
const obj = reactive({foo: {bar: {name: '张三'}}
})
watch(obj, (newVal: any, oldVal: any) => {console.log(newVal, oldVal)
})
</script>
与上方 ref 一样,由于对象是引用类型,新值和旧值指向同一内存地址,所以值一样。
注意,不能直接侦听响应式对象的属性值,例如:
const obj = reactive({foo: {bar: {name: '张三'}}
})
watch(obj.foo.bar.name, (newVal: any, oldVal: any) => {console.log(newVal, oldVal)
})
会发生警告:
这是因为 watch 的 source 接受的参数不符合要求,只能接受一个 getter , effect , ref , reactive 或者元素是这几个类型的数组。官方建议用一个返回该属性的 getter 函数:
const obj = reactive({foo: {bar: {name: '张三'}}
})watch(() => obj.foo.bar.name,(newVal: any, oldVal: any) => {console.log(newVal, oldVal)}
)
当输入框值改变时:
4.watch的配置项
- deep :布尔值,深度监听,默认 false ;
- immediate :布尔值,在创建侦听器时,立即执行一遍回调,默认 false ;
- plush :字符串,"pre":组件更新之前调用,"sync":同步执行,"post":组件更新之后执行,默认"pre";
- once :布尔值,回调只在源变化时触发一次,默认 false 。