Vue3watch监视

185 阅读3分钟

一句总结:Vue3中的watch用于监听数据的变化并在变化时执行相应的回调函数,支持深度监听和监听多个数据源,是Vue 3响应式系统中处理数据变化的关键机制之一。

watch只能监视四种数据

  1. ref定义的数据
  2. reactive定义的数据
  3. 函数返回一个值
  4. 一个包含上述内容的数组

情况一:watch监视ref定义的基本类型数据

<template>
  <div>
    <h3>求和{{ sum }}</h3>
    <button @click="changeSum">点我 + 1</button>
  </div>
</template>

<script lang="ts" setup name="Person">
  import { ref, watch } from "vue";
  let sum = ref(0)
  function changeSum() {
    sum.value += 1
  }
  watch(sum, (newValue, oldValue)=>{
    console.log("sum发生了变化", newValue, oldValue);
  })
</script>

image.png

总结:

  1. watch监视ref定义的基本类型数据,直接写数据名,不用.value,实际监视的是其value值的改变;
  2. watch调用会有一个返回值 stopwatch,用于停止监听的函数

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

<template>
  <div>
    <div>姓名:{{ person.name }}</div>
    <div>年龄:{{ person.age }}</div>
    <button @click="changeName">修改姓名</button>
    <button @click="changePerson">修改人</button>
  </div>
</template>

<script lang="ts" setup name="Person">
  import { ref, watch } from "vue";
  let person = ref({
    name: 'zhangsan',
    age: 20
  })
  function changeName() {
    person.value.name = 'lisi'
  }
  function changePerson() {
    person.value = {
      name: 'lisi',
      age: 10
    }
  }
  const stopwatch = watch(person, (newValue, oldValue)=>{
    console.log("sum发生了变化", newValue, oldValue);
  }, {deep: true})
</script>

image.png

监视ref定义的对象类型数据,直接写数据名,监视的是对象的地址值,如果想监视对象内部的数据,需要手动使用deep:true开启深度监视

watch监听ref定义的对象类型数据时,如果修改对象中某一个值,newValue和oldValue是一样的

image.png

因为对象的地址值没有发生变化

情况三:watch监听reactive定义的对象类型数据

<template>
  <div>
    <div>姓名:{{ person.name }}</div>
    <div>年龄:{{ person.age }}</div>
    <button @click="changeName">修改姓名</button>
    <button @click="changePerson">修改人</button>
  </div>
</template>

<script lang="ts" setup name="Person">
  import { reactive, watch } from "vue";
  let person = reactive({
    name: 'zhangsan',
    age: 20
  })
  function changeName() {
    person.name = 'lisi'
  }
  function changePerson() {
    Object.assign(person, {
      name: 'lisi',
      age: 10
    })
  }
  const stopwatch = watch(person, (newValue, oldValue)=>{
    console.log("sum发生了变化", newValue, oldValue);
  })
</script>

watch监听reactive定义的对象类型数据,隐式创建了深度监视

情况四:监视ref或reactive定义的对象类型数据中的某个数据

  1. 如果该属性是对象类型,可以直接写,也可以写成函数形式
  2. 如果该属性不是对象类型,需要写成函数形式
<template>
  <div>
    <div v-for="(game,index) in person.game" :key="index">
      <span>{{game}}</span>
    </div>
    <button @click="changeName">修改姓名</button>
    <button @click="changeGame1">修改游戏1</button>
  </div>
</template>

<script lang="ts" setup name="Person">
  import { reactive, watch } from "vue";
  let person = reactive({
    name: 'zhangsan',
    age: 20,
    game: {
      game1: '三角洲行动',
      game2: '1999'
    }
  })
  function changeName() {
    person.name = 'lisi'
  }
  function changeGame() {
    person.game.game1 = '使命召唤'
  }
  watch(()=>person.name, (newValue, oldValue)=>{
    console.log("name发生了变化", newValue, oldValue);
  })
  watch(()=>person.game.game1,(newValue, oldValue)=>{
    console.log("game1发生了变化", newValue, oldValue);
  })
</script>

image.png

如果该属性是对象类型,直接写监听不到数据的变化,因为已经不是原来的对象

<template>
  <div>
    <div v-for="(game,index) in person.game" :key="index">
      <span>{{game}}</span>
    </div>
    <button @click="changeGame">修改游戏</button>
  </div>
</template>

<script lang="ts" setup name="Person">
  import { reactive, watch } from "vue";
  let person = reactive({
    name: 'zhangsan',
    age: 20,
    game: {
      game1: '三角洲行动',
      game2: '1999'
    }
  })
  function changeGame() {
    person.game = {
      game1: '使命召唤',
      game2: '崩铁'
    }
  }
  watch(person.game,(newValue, oldValue)=>{
    console.log("game1发生了变化", newValue, oldValue);
  })
</script>

image.png 这时就需要写成函数形式

<script lang="ts" setup name="Person">
  import { reactive, watch } from "vue";
  let person = reactive({
    name: 'zhangsan',
    age: 20,
    game: {
      game1: '三角洲行动',
      game2: '1999'
    }
  })
  function changeGame() {
    person.game = {
      game1: '使命召唤',
      game2: '崩铁'
    }
  }
  watch(()=>person.game,(newValue, oldValue)=>{
    console.log("game1发生了变化", newValue, oldValue);
  })
</script>

image.png

监视多个数据

<script lang="ts" setup name="Person">
  import { reactive, watch } from "vue";
  let person = reactive({
    name: 'zhangsan',
    age: 20,
    game: {
      game1: '三角洲行动',
      game2: '1999'
    }
  })
  function changeName() {
    person.name = 'lisi'
  }
  function changeGame() {
    person.game = {
      game1: '使命召唤',
      game2: '崩铁'
    }
  }
  watch([()=>person.name, ()=>person.game],(newValue, oldValue)=>{
    console.log("game1发生了变化", newValue, oldValue);
  })
</script>

watchEffect

立即运行一个函数,同时响应式的追踪其依赖,并在依赖更改时重新执行该函数;也就是函数中用到哪些属性,就监听哪些属性

<template>
  <div>
    <div>{{ person.age }}</div>
    <button @click="changeAge">修改年龄</button>
  </div>
</template>

<script lang="ts" setup name="Person">
  import { reactive, watchEffect } from "vue";
  let person = reactive({
    name: 'zhangsan',
    age: 20,
  })
  function changeAge() {
    person.age += 1
  }
  watchEffect(()=>{
    if(person.age >= 30) {
      console.log("而立");
    }
  })
</script>

image.png