watch监听

watch监听

参考地址:https://cn.vuejs.org/api/reactivity-core.html

特别注意:凡是监视对象类型,只要引用没有发生变化,oldValue和newValue一致。

作用:监视数据的变化(和Vue2中的watch作用一致)

特点:Vue3中的watch只能监视以下四种数据

ref定义的数据。

reactive定义的数据。

​ 函数返回一个值(getter函数)。

​ 一个包含上述内容的数组。

我们在Vue3中使用watch的时候,通常会遇到以下几种情况:

情况一 监视ref定义的【基本类型】数据

​ 监视ref定义的【基本类型】数据:直接写数据名即可,不用添加.value,监视的是其value值的改变。

<template>
  <div class="person">
    <h2>监视ref定义的【基本类型】数据:直接写数据名即可,监视的是其value值的改变。</h2>
    <h2>当前求和数据: {{sum}}</h2>
    <button @click="changeSum">点我sum + 1</button>
  </div>
</template>

<script setup lang="ts" name="Person">
  import {ref, watch} from 'vue'

  //数据
  let sum = ref(0)
  
  //方法
  function changeSum() {
    sum.value += 1;
  }

  //监视
  const stopWatch =  watch(sum, (newVlaue, oldValue) => {  //参数说明:监视对象, 回调函数
    console.log('sum变化了从' + oldValue + "变为了" + newVlaue);
    if(sum.value >= 10) {
      stopWatch()   //返回的是一个停止监听的函数
    }
  })
</script>

<style>
.person {
  background-color: skyblue;
  box-shadow: 0 0 10px; /* 盒子阴影 */
  border-radius: 10px;
  padding: 20px;
}

button {
  margin: 0 5px;
}
</style>

情况二 监视ref定义的【对象类型】数据

监视ref定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。

注意:

​ 若修改的是ref定义的对象中的属性,newValueoldValue 都是新值,因为它们是同一个对象。

​ 若修改整个ref定义的对象,newValue 是新值, oldValue 是旧值,因为不是同一个对象了。

<template>
  <div class="person">
    <h2>监视ref定义的【对象类型】数据</h2>
    <h2>姓名: {{person.name}}</h2>
    <h2>年龄: {{person.age}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changePerson">修改人</button>
  </div>
</template>

<script setup lang="ts" name="Person">
  import {ref, watch} from 'vue'

  //数据
  let person = ref({
    name: '张三',
    age: 18
  })
  
  //方法
  function changeName() {
    person.value.name += "~";
  }

  function changeAge() {
    person.value.age += 1;
  }

  function changePerson() {
    person.value = {name: '李四', age: 90};
  }

  //监视
  // watch(person, (newValue, oldValue) => { //直接这样写,只会监视person这个对象的变化,对于其内部的变化不会触发
  //   console.log('person从: ', oldValue, "变为: ", newValue);
  // });

  //深度监视
  watch(person, (newValue, oldValue) => { //需要传递第三个参数 {deep:true}
    console.log('person从: ', oldValue, "变为: ", newValue);
  }, {deep: true}); //### 还可以添加参数 {immediate:?}  这样初始化的时候也会监视一下

</script>

<style>
.person {
  background-color: skyblue;
  box-shadow: 0 0 10px; /* 盒子阴影 */
  border-radius: 10px;
  padding: 20px;
}

button {
  margin: 0 5px;
}
</style>

情况三 监视reactive定义的【对象类型】数据

​ 监视reactive定义的【对象类型】数据,且默认开启了深度监视。

<template>
  <div class="person">
    <h2>监视reactive定义的【对象类型】数据,且默认开启了深度监视。</h2>
    <h2>姓名: {{person.name}}</h2>
    <h2>年龄: {{person.age}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changePerson">修改人</button>
  </div>
</template>

<script setup lang="ts" name="Person">
  import {reactive, watch} from 'vue'

  //数据
  let person = reactive({
    name: '张三',
    age: 18
  })
  
  //方法
  function changeName() {
    person.name += "~";
  }

  function changeAge() {
    person.age += 1;
  }

  function changePerson() {
    // person = {name: '李四', age: 90};  //这里由于使用了reactive所以不能直接修改对象

    //注意:这里这个引用没有发生变化哦
    Object.assign(person, {name: '李四', age: 90}); //需要使用这种方式,响应式才不会被破坏
  }

  //监视 因为person是reactive定义的 默认深度监视,无法关闭
  watch(person, (newValue, oldValue) => { //因为person是reactive定义的,直接这样写,默认就开启了deep监视
    console.log('person从: ', oldValue, "变为: ", newValue);
  });

</script>

<style>
.person {
  background-color: skyblue;
  box-shadow: 0 0 10px; /* 盒子阴影 */
  border-radius: 10px;
  padding: 20px;
}

button {
  margin: 0 5px;
}
</style>

情况四 监视refreactive定义的【对象类型】数据中的某个属性

监视refreactive定义的【对象类型】数据中的某个属性,注意点如下:

  1. 若该属性值不是【对象类型】,需要写成函数形式。
  2. 若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。

结论:监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。

<template>
  <div class="person">
    <h2>姓名:{{ person.name }}</h2>
    <h2>年龄:{{ person.age }}</h2>
    <h2>汽车:{{ person.car.c1}}、{{ person.car.c2 }}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changeOneCar">修改第一台车</button>
    <button @click="changeTwoCar">修改第二台车</button>
    <button @click="changeCar">修改整个车</button>    
  </div>
</template>

<script setup lang="ts" name="Person">
  import {reactive, watch} from 'vue'
  
  //数据
  let person = reactive({
    name: '张三',
    age: 20,
    car: {
      c1: '小米',
      c2: '奔驰'
    }
  })

  //方法
  function changeName() {
    person.name += '~';
  }

  function changeAge() {
    person.age += 1;
  }
  
  function changeOneCar() {
    person.car.c1 += '~';
  }

  function changeTwoCar() {
    person.car.c2 += '~';
  }

  function changeCar() {
    Object.assign(person, {
      name: '李四',
      age: 30,
      car: {
        c1: '大众',
        c2: '马自达'
      }
    })
  }

  //监听, 为了监视响应式对象中的某个对象,且该属性是:基本数据类型,要写为函数式
  watch(() => person.name, (newValue, oldValue) => {
    console.log('person.name变化了', newValue, oldValue);
  })


  //##### 监听对象中的对象 ######
  // watch(person.car, (newValue, oldValue) => {   //可以发现监视响应式对象中的对象属性ok的,但是修改整个外层对象时,又无法监听到
  //   console.log('person.car变化了', newValue, oldValue);
  // })

  // watch(() => person.car, (newValue, oldValue) => { //而使用函数式后 car整体变化ok了,但是细节变化又不行了,因为监听变化的是car变量的引用了
  //   console.log('person.car变化了', newValue, oldValue);
  // })

  //##### 所以得出如果想要 监听对象中的对象 细枝末节变和整体变都可以监听到的最佳实践 ######
  watch(() => person.car, (newValue, oldValue) => {
    console.log('person.car变化了 或者 car中的属性变化了', newValue, oldValue);
  }, {deep: true})

  // watch(() => person.car.c1, (newValue, oldValue) => {
  //   console.log('person.car.c1变化了', newValue, oldValue);
  // })

</script>

<style>
.person {
  background-color: skyblue;
  box-shadow: 0 0 10px; /* 盒子阴影 */
  border-radius: 10px;
  padding: 20px;
}

button {
  margin: 0 5px;
}
</style>
监听对象中的对象最佳实践:
  //##### 监听对象中的对象 ######
  // watch(person.car, (newValue, oldValue) => {   //可以发现监视响应式对象中的对象属性ok的,但是修改整个外层对象时,又无法监听到
  //   console.log('person.car变化了', newValue, oldValue);
  // })

  // watch(() => person.car, (newValue, oldValue) => { //而使用函数式后 car整体变化ok了,但是细节变化又不行了,因为监听变化的是car变量的引用了
  //   console.log('person.car变化了', newValue, oldValue);
  // })

  //##### 所以得出如果想要 监听对象中的对象 细枝末节变和整体变都可以监听到的最佳实践 ######
  watch(() => person.car, (newValue, oldValue) => {
    console.log('person.car变化了 或者 car中的属性变化了', newValue, oldValue);
  }, {deep: true})

情况五 监视上诉的多个数据

​ 监视上述的多个数据,即我们的watch使用时第一个参数可以传递一个数组,只要其中的一个发生变化都会执行回调函数。这里对应的写法都推荐函数式。说明:基本类型也可以使用函数式写法如:() => name.value

<template>
  <div class="person">
    <h2>姓名:{{ person.name }}</h2>
    <h2>年龄:{{ person.age }}</h2>
    <h2>汽车:{{ person.car.c1}}、{{ person.car.c2 }}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changeOneCar">修改第一台车</button>
    <button @click="changeTwoCar">修改第二台车</button>
    <button @click="changeCar">修改整个车</button>    
  </div>
</template>

<script setup lang="ts" name="Person">
  import {reactive, ref, watch} from 'vue'
  
  //数据
  let name = ref(0);
  let person = reactive({
    name: '张三',
    age: 20,
    car: {
      c1: '小米',
      c2: '奔驰'
    }
  });

  //方法
  function changeName() {
    person.name += '~';
  }

  function changeAge() {
    person.age += 1;
  }
  
  function changeOneCar() {
    person.car.c1 += '~';
  }

  function changeTwoCar() {
    person.car.c2 += '~';
  }

  function changeCar() {
    Object.assign(person, {
      name: '李四',
      age: 30,
      car: {
        c1: '大众',
        c2: '马自达'
      }
    })
  }

  //监听
  watch([() => person.name, () => person.car.c1], (newValue, oldValue) => {
    console.log('person.name变化了 或者 person.car.c1', newValue, oldValue);
  }, {deep: true})

</script>

<style>
.person {
  background-color: skyblue;
  box-shadow: 0 0 10px; /* 盒子阴影 */
  border-radius: 10px;
  padding: 20px;
}

button {
  margin: 0 5px;
}
</style>
posted @ 2024-12-24 09:43  如此而已~~~  阅读(84)  评论(0)    收藏  举报
//雪花飘落效果