vue3中的watch比起vue2中的watch有了些许的变化,我们使用composition api来写

基本数据类型的监听,在vue3中被ref定义的数据通常在使用时需要在后面加一个.value,但是这里需要监听整个RefImpl对象才能起作用,所以说在写watch时不需要加.value

<template>
  当前求和为:{{ sum }}
  <button @click="sum++">点我++</button>
</template>

<script>
import { ref, watch } from "vue";
export default {
  name: "App",
  setup() {
    let sum = ref(0);
    watch(sum, (newValue, oldValue) => {
      console.log("sum变了", newValue, oldValue);
    },{immediate:true});
    return {
      sum,
    };
  },
};
</script>

vue3中的watch变成了函数形式,有三个参数,第一个是监听的对象,第二个是监听的回调,由于setup不需要考虑this的指向问题,所以可以直接在watch中写箭头函数,第三个是监听的配置项;如果有两个数据需要监听可以直接写成两个watch函数

watch(sum, (newValue, oldValue) => {
 	console.log("sum变了", newValue, oldValue);
});
watch(msg, (newValue, oldValue) => {
  	console.log("msg变了", newValue, oldValue);
});

或者把监听的对象写成一个数组,这样写的话,oldValue和newValue全都会变成数组

watch([sum,msg], (newValue, oldValue) => {
   	console.log("sum或msg变了", newValue, oldValue);
});

对象使用watch和基本数据类型是一样的,如果使用reactive定义的对象可以直接写,但是使用ref定义的对象需要加.value,这是因为监视对象时要对这个对象的Proxy对象生效,如果用ref来定义对象它的value属性才是这个对象的Proxy。如果写了.value那么他对Proxy的监视默认是深度监视,且无法关闭,配置deep:false无效,如果不写.value这里可以在后面加上deep:true,实现深度监视。

<template>
  <h2>姓名:{{ obj.name }}</h2>
  <h2>年龄:{{ obj.age }}</h2>
  <button @click="obj.age++">年龄加加</button>
  <h2>朋友名字:{{obj.friend.name}}</h2>
  <h2>朋友年龄:{{obj.friend.age}}</h2>
  <button @click="obj.friend.name += '@'">朋友名字变化</button>
</template>

<script>
import { reactive, watch, ref } from "vue";
export default {
  setup() {
    let obj = reactive({
      name: "张三",
      age: 20,
      friend:{
        name:'李四',
        age:21
      }
    });
    watch(obj, (newValue, oldValue) => {
      console.log("obj改变了", newValue, oldValue);
    });
    // let obj = ref({
    //   name: "张三",
    //   age: 20,
    //   sex: "男",
    //   friend:{
    //     name:'李四',
    //     age:21
    //   }
    // });
    //如果使用ref来定义对象,watch需要写成以下两种形式才能生效
    // watch(()=>obj.value, (newValue, oldValue) => {
    //   console.log("年龄改变了", newValue, oldValue);
    // });
    // watch(()=>obj, (newValue, oldValue) => {
    //   console.log("年龄改变了", newValue, oldValue);
    // },{deep:true});
    return {
      obj,
    };
  },
};
</script>

但是这里对对象的监听又有点问题,数据改变时无法拿到oldValue,使用reactive定义的对象会出现这个问题,由于ref在定义响应式对象时也调用了reactive中的方法,所以这个问题目前还无法直接解决,可以通过直接监听对象中的属性来解决,或者把想要监听的属性通过ref来定义
数据改变但是oldValue和newValue是相同的
如果只对对象中的某个属性进行监听,需要把第一个参数写成函数的形式才会生效

watch(()=>obj.age, (newValue, oldValue) => {
 	console.log("年龄改变了", newValue, oldValue);
});

如果要监听对象中的多个属性可以把第一个参数写成数组的形式

watch([()=>obj.age,()=>obj.name], (newValue, oldValue) => {
 	console.log("年龄或者名字改变了", newValue, oldValue);
});

但是如果对象是嵌套多层的,直接监听最外侧对象可以检测到整个对象中的数据的变化

 watch(obj, (newValue, oldValue) => {
  	console.log("对象改变了", newValue, oldValue);
 });

如果想要检测对象中的对象是否发生变化,直接写是无效的

 watch(()=>obj.friend, (newValue, oldValue) => {
   	console.log("年龄改变了", newValue, oldValue);
 });//无法检测friend对象中的数据变化

此时需要加上配置项deep:true,监听奏效

watch(()=>obj.friend, (newValue, oldValue) => {
  	console.log("朋友改变了", newValue, oldValue);
},{deep:true});

vue3中的监听最好用的还是watchEffect,可以自动识别回调中使用了哪个数据来对该数据进行监听,有点像计算属性,但是computed注重的是计算产生的值,所以需要写返回值,watchEffect注重数据变化时回调函数的执行,不需要返回值。

watchEffect(()=>{
	//可以直接写回调的逻辑,用到了哪个数据对哪个数据实现监听,只要回调中写到的数据发生变化,方法就会重新执行一次      
})
Logo

前往低代码交流专区

更多推荐