• vue3学习(四)--- watch和watchEffect监听


    watch

    watch() 默认是懒侦听的初始化不触发,只有在侦听源发生变化时才执行回调函数

    watch的结构:

    • source 侦听源
    • callback 回调函数
    • options 额外参数
      1. immediate:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined
      2. deep:如果源是对象,强制深度遍历,以便在深层级变更时触发回调
      3. flush:调整回调函数的刷新时机
      4. onTrack / onTrigger:调试侦听器的依赖(可以在里面debugger等操作)
    function watch<T>(
      source: WatchSource<T>, 
      callback: WatchCallback<T>,
      options?: WatchOptions
    ): StopHandle
    
    • 1
    • 2
    • 3
    • 4
    • 5

    source侦听源不同类型

    这个来源可以是以下几种:

    • 一个 ref
    • 一个reactive
    • 一个函数,返回一个值
    • 或是由以上类型的值组成的数组

    侦听ref

    let num = ref(20)
    
    //  基础类型 watch(要监听的响应式数据,回调(new,old))
    watch(num, (newval, oldval) => {
      console.log(newval, oldval)
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    侦听reactive

    使用reactive监听深层对象开启和不开启deep 效果一样

    import { ref, watch ,reactive} from 'vue'
     
    let message = reactive({
        nav:{
            bar:{
                name:""
            }
        }
    })
    watch(message, (newVal, oldVal) => {
        console.log('新的值----', newVal);
        console.log('旧的值----', oldVal);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    侦听没有响应式的数据

    当我们像侦听到ref/reactive里面属性时,由于不是响应式的原因直接侦听是没有效果的。
    watch对这种数据做了处理,用函数返回的形式对数据进行监听
    源码讲解点这里

    import { ref, watch ,reactive} from 'vue'
     
    let message = reactive({
        name:"",
        name2:""
    }) 
    watch(()=>message.name, (newVal, oldVal) => {
        console.log('新的值----', newVal);
        console.log('旧的值----', oldVal);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    由于是因为不是响应式数据才需要用函数返回的形式。那么我们也可以将数据转为响应式的比如下面的写法:

    import { ref, watch ,reactive} from 'vue'
     
    let message = reactive({
        name:"",
        name2:""
    }) 
    watch(toRef(message,'name'), (newVal, oldVal) => {
        console.log('新的值----', newVal);
        console.log('旧的值----', oldVal);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    侦听多个源

    第一种就是可以分开创建多个watch侦听

    import { ref, watch ,reactive} from 'vue'
     
    let message = ref('')
    let message2 = ref('')
     
    watch(message, (newVal, oldVal) => {
        console.log('新的值----', newVal);
        console.log('旧的值----', oldVal);
    })
    
    watch(message2, (newVal, oldVal) => {
        console.log('新的值----', newVal);
        console.log('旧的值----', oldVal);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    第二种就是以数组的形式进行侦听,同样回调返回的结果也是以数组的形式展现的。

    import { ref, watch ,reactive} from 'vue'
     
    let message = ref('')
    let message2 = ref('')
     
    watch([message,message2], (newVal, oldVal) => {
        console.log('新的值----', newVal);
        console.log('旧的值----', oldVal);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    watchEffect

    立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
    如果用到message 就只会监听message 就是用到几个监听几个 而且是非惰性 会默认调用一次

    // 页面进入立即触发监听
    watchEffect(() => {
      // 凡是写在这里的数据,只要发生改变 都会触发这里的代码
      console.log(' objRea.num', objRea.num)
      if (objRea.num > 31) {
        objRea.num = 0
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    清除副作用

    就是在触发监听之前会调用一个函数可以处理你的逻辑

    import { watchEffect, ref } from 'vue'
    let message = ref<string>('')
    let message2 = ref<string>('')
     watchEffect((oninvalidate) => {
        console.log('message', message.value);
        console.log('message2', message2.value);
        oninvalidate(()=>{
            console.log('初始化不触发,只有数据发生变化的时候才触发,触发的机制始终是最前的,oninvalidate不管放在哪个位置都会在message message2打印之前触发')
        })
    
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    清除侦听

    import { watchEffect, ref } from 'vue'
    let message = ref<string>('')
    let message2 = ref<string>('')
    
    const stop = watchEffect((oninvalidate) => {
        console.log('message', message.value);
        console.log('message2', message2.value);
        oninvalidate(()=>{
            console.log('初始化不触发,只有数据发生变化的时候才触发,触发的机制始终是最前的,oninvalidate不管放在哪个位置都会在message message2打印之前触发')
        })
    })
    
    合理的位置调用stop 停止侦听
    stop()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    flush用法

    上面提到的option额外参数在watchEffect中同样适用,flush参数更适合用在watchEffect中。

    flush默认是pre,主要区别在于侦听器的更新时间,一般会选择使用post 在组件更新后执行。这时候dom都已经更新完成了。
    在这里插入图片描述

    
    import { watchEffect, ref } from 'vue'
    let message = ref<string>('')
    let message2 = ref<string>('')
     watchEffect((oninvalidate) => {
       	let ele = document.querySelector('#aaa'); 这里拿到的是dom节点 所以说flush最好使用post在更新后执行
        console.log('message2', message2.value);
    },{
        flush:"post",
        onTrigger () {
            
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    【附源码】Python计算机毕业设计体育场馆预定网站
    【Docker 内核详解】namespace 资源隔离(一):进行 namespace API 操作的 4 种方式
    ue unreal 虚幻 invalid HTTP response code received 问题
    【Linux常见指令1】
    多旋翼无人机仿真 rotors_simulator:基于PID控制器的位置控制
    twitter推文采集案例
    通过docker进行部署 Zookeeper、Kafka集群
    WPF(二) WPF核心进阶
    云桥通+跨境电商:SDWAN企业组网优化跨境网络案例
    【图论】Linova and Kingdom—CF1336A
  • 原文地址:https://blog.csdn.net/weixin_43932245/article/details/133746442