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

文章目录

  • watch
    • source侦听源不同类型
      • 侦听ref
      • 侦听reactive
      • 侦听没有响应式的数据
      • 侦听多个源
  • watchEffect
    • 清除副作用
    • 清除侦听
    • flush用法

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

source侦听源不同类型

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

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

侦听ref

let num = ref(20)

//  基础类型 watch(要监听的响应式数据,回调(new,old))
watch(num, (newval, oldval) => {
  console.log(newval, oldval)
})

侦听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);
})

侦听没有响应式的数据

当我们像侦听到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);
})

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

import { ref, watch ,reactive} from 'vue'
 
let message = reactive({
    name:"",
    name2:""
}) 
watch(toRef(message,'name'), (newVal, oldVal) => {
    console.log('新的值----', newVal);
    console.log('旧的值----', oldVal);
})

侦听多个源

第一种就是可以分开创建多个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);
})

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

import { ref, watch ,reactive} from 'vue'
 
let message = ref('')
let message2 = ref('')
 
watch([message,message2], (newVal, oldVal) => {
    console.log('新的值----', newVal);
    console.log('旧的值----', oldVal);
})

watchEffect

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

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

清除副作用

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

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打印之前触发')
    })

})

清除侦听

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()

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 () {
        
    }

你可能感兴趣的:(vue3,学习,vue.js,前端)