watch监视的四种类型
- ref定义的基本数据
- ref定义的对象类型
- reactive定义的数据
- 函数的返回值(getter)
- 包含上述内容的数组
监视ref
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script setup lang="ts">
import { watch, ref } from 'vue'; let sum = ref(0); const stopWatch = watch(sum, (newValue, oldValue) => { //导入的变量含义只和顺序有关(value0, value1)同效,如果只导入一个(value0),value0就相当于newValue console.log(`Sum changed from ${oldValue} to ${newValue}`); if(newValue >= 5){ // newValue大于等于5后停止监视 stopWatch(); } });
function addSum() { sum.value += 1; }
</script>
|
监视ref定义的对象
监视对象和监视ref的基本语法没什么区别,重要的是watch后面的一个配置项。
要注意的是,如果没有添加任何配置项,仅仅改变对象的属性不会被监视到。只有改变整个对象的值才会被监视到。如果要让改变对象的属性也能被监视到,就需要添加一个{deep:true}的配置项。
注意:{deep:true} 监视对象的属性时,属性发生改变后,传入的oldValue和newValue是一样的。这是因为在监视之前,对象的属性就已经被改变了,这时不管如何监视,都已经找不到旧值了。那为什么覆盖整个对象时oldValue可以被监视到?可以这样理解:覆盖整个对象时,它在内存里创建了一个新的地址赋值给对象,所以 旧值得以保留。而当改变属性时,并没有新的地址,而是在原地址的数据上进行的修改。这个解释放到改变普通ref变量上可以正常监视,也能说的通。
{immedia:true} 的意思是在初始化定义该对象时,也触发对其的监视。oldValue为undefined。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <script setup lang="ts">
import { watch, ref } from 'vue'; let person = ref({ name: 'john', age: 12 });
const stopWatch = watch(person, (newValue, oldValue)=> { console.log('person changed:', newValue, oldValue); }, {deep: true, immediate: true});
function changName(){ person.value.name += 'mary'; } function changAge(){ person.value.age += 1; }
function changeALl(){ person.value = { name: 'newName', age: 20 }; }
</script>
|
监视reactive
使用方法与ref相比除了不需要使用.value基本没有区别。
但是需要注意的是,reactive定义的对象不能直接用等号覆盖,必须要使用Object.assign来改值。这就导致覆盖reactive对象时实际上并没有给这个对象创建一个新的地址,而是使用一个函数将对象的值一个一个改变,这就导致oldValue与newValue是一致的。
还有一个区别是监视reactive时,是默认开启{deep:true}的,而且是无法关闭的。这对reactive管理深层次属性的特性有帮助。
监视对象中的属性
如果直接写
1 2 3 4
| watch(person.name, (newName, oldName) => { console.log(`Name changed from ${oldName} to ${newName}`); });
|
是会报错的。
监视对象的属性需要使用箭头函数的形式。
1 2 3 4
| watch(() => person.name, (newName, oldName) => { console.log(`Name changed from ${oldName} to ${newName}`); });
|
同时,如果要监视的属性也是对象,需要启用deep才能监视到内部的属性。
监视数组
只需要在监视对象的参数上用一个[]将所有要监视的对象括起来就可以了。
就像这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <script setup lang="ts">
import { watch, reactive, ref } from 'vue';
let test = ref("Hello World");
let person = reactive({ name: 'John Doe', age: 30, car: { model: 'Toyota', year: 2020, } })
watch([() => person.name, () => person.car], (newName, oldName) => { console.log(oldName, '->', newName); }, {deep : true});
function updateName() { person.name = 'Jane Smith'; } function updateCar() { person.car = { model: 'Ford', year: 2021 }; } function updateCarModel() { person.car.model = 'Honda'; }
</script>
|
watchEffect
是一个自动监视的函数。何为自动?就是不需要自己指出监视哪些变量,只要你用到了这个对象,他就会帮你自动监视。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script setup lang="ts">
import { ref, watchEffect} from 'vue';
let num = ref(0); watchEffect(() => { console.log(`num is: ${num.value}`); if(num.value > 5) { num.value = 0; } }); function updateNum() { num.value++; }
</script>
|
有点强