阅读 105

Vue3-笔记-我对watch侦听器的理解

侦听器是干嘛用的?

理论知识讲:当被侦听的信息发生变化时,触发侦听器的回调函数,从而在侦听器的回调函数中执行一些后续的操作。

典型的场景:

当路由参数发生变化后,重新调用接口获取组件的数据

这个操作计算属性能做到吗?显然不能,因为计算属性只能处理同步操作,而调用接口获取组件数据的操作时异步操作,这时,侦听器的作用就出现了。

由此可见侦听器是会经常用到的,一定要熟练掌握它!

<template>
  <div>侦听器练习</div>
  <hr>
<div>{{count}}</div>
<button @click="count++">点击</button>
</template>
复制代码
import { ref, watch } from 'vue'
export default {
  name: 'App',
  setup () {
    const count = ref(0)
    // 基于侦听器监听数据变化
    // 这里有个watch的基本规则:被侦听的数据必须是响应式的
    watch(count, (newValue, oldValue) => {
      // newValue表示修改后的值
      // oldValue表示修改前的值
      console.log(newValue, oldValue)
    })
    return { count }
  }
}
复制代码

侦听基本数值.jpg 以上只是侦听了基本数据类型

当侦听对象类型的数据

<template>
  <div>{{obj.msg}}</div>
   <button @click="handleClick">侦听对象</button>
</template>
复制代码
import { watch, reactive } from 'vue'
export default {
  name: 'App',
  setup () {
  // 创建一个响应式对象obj
    const obj = reactive({
      msg: 'tom'
    })
    // 点击修改msg为'jerry
    const handleClick = () => {
      obj.msg = 'jerry'
    }
    // 侦听obj变化
    watch(obj, (nVal, oVal) => {
    // 最终发现新值和旧值竟然相同
      console.log(nVal, oVal)
    })
    return { count, obj, handleClick }
  }
}
复制代码

新旧值一样.jpg

原因:如果侦听对象,那么侦听器的回调函数的两个参数时一样的结果,表示最新的对象数据,此时,也可以直接读取被侦听的对象,那么得到的值也是最新的值。

所以就没必要使用形参了,直接通过对象点属性的方法去侦听即可

 // 侦听obj变化
    watch(obj, () => {
    console.log(obj.msg)
    })
复制代码

侦听器的第三种场景,侦听多个值时:

<template>
<div>{{n1}}</div>
<div>{{n2}}</div>
<button @click="handleClick">侦听对象</button>
</template>
复制代码
import { ref, watch} from 'vue'
export default {
  name: 'App',
  setup () {
    // 侦听多个值
    const n1 = ref(1)
    const n2 = ref(2)
    const handleClick = () => {
      n1.value = 3
      n2.value = 4
    }
    // 侦听多个值用数组包起来的
    watch([n1, n2], (v1,v2) => {
    // 侦听后得到的是新的数组值
      console.log(v1,v2)
      // 形参v1代表最新值
      // 形参v2代表原有值
    })
    return { handleClick, n1, n2 }
  }
}
复制代码

当需要侦听多个值的时候,这就会有它的价值,侦听器的第一个参数是可以接收数组的,侦听到的结果也是数组,数据顺序一致。

侦听对象的单个属性

<template>
  <div>侦听器练习</div>
  <hr>
<div>{{stuInfo.uname + '===' + stuInfo.age}}</div>
<button @click="handleClick">点击</button>
</template>
复制代码
import { reactive, watch } from 'vue'
export default {
  name: 'App',
  setup () {
    const stuInfo = reactive({
      uname: 'lisi',
      age: 12
    })
    const handleClick = () => {
      stuInfo.age = 13
    }
    // 如果被侦听的是表达式,需要用函数方式
    // 侦听过多数据会影响性能,所以如果真是需要侦听对象中的一个数据,那么就按照下面这样写就可以了
    watch(() => stuInfo.age, (v1, v2) => {
      // 这里打印出来后发现新值和旧值都能拿得到
      console.log(v1, v2)
    })
    return { stuInfo, handleClick }
  }
}
复制代码

总结:如果侦听对象中的单个属性,需要使用函数的方式,侦听更少的数据有利于提高性能。

watch方法的配置选项(watch的第二个参数)

<template>
  <div>侦听器练习</div>
  <hr>
<div>{{stuInfo.uname + '===' + stuInfo.age}}</div>
<div>{{stuInfo.friend.uname}}</div>
<button @click="handleClick">点击</button>
</template>
复制代码
import { reactive, watch } from 'vue'
export default {
  name: 'App',
  setup () {
    const stuInfo = reactive({
      uname: 'lisi',
      age: 12,
      friend: {
        uname: 'zhangsan'
      }
    })
    const handleClick = () => {
      stuInfo.age = 13
      stuInfo.friend.uname = 'wangwu'
    }
    // 如果被侦听的是表达式,需要用函数方式
    // 侦听过多数据会影响性能,所以如果真是需要侦听对象中的一个数据,那么就按照下面这样写就可以了
    watch(() => stuInfo.age, (v1, v2) => {
      // 这里打印出来后发现新值和旧值都能拿得到
      console.log(v1, v2)
    })

    watch(() => stuInfo.friend, () => {
      // 侦听器的回调不是一进来就会被调用的,如果需要一上来就被调用
      console.log('stuInfo')
      // 需要在回调函数后面加上{immediate: true}
      // 这时去修改friend中的值,看看侦听器会不会打印
      // 点击后发现,名字换了,但是没有侦听到
      // 这时就需要加上另一个选项:deep:true 代表深度侦听
    }, {
      // 立即调用侦听器回调函数
      // 组件渲染后,立即触发一次
      immediate: true,
      // 被侦听的内容需要是函数的写法 ()=> stuInfo.friend
      deep: true
    })
    return { stuInfo, handleClick }
  }
}
复制代码

这里有个重点:当使用深度侦听时,要确保 被侦听的内容是函数的写法:

() => stuInfo.friend
复制代码

总结一哈:

1.immediate:true,表示组件渲染时立即调用 2. deep:true,表示深度侦听对象里面的子属性(被侦听的内容需要是函数的写法)

文章分类
前端
文章标签