watch() 默认是懒侦听的初始化不触发,只有在侦听源发生变化时才执行回调函数。
watch的结构:
immediate
:在侦听器创建时立即触发回调。第一次调用时旧值是 undefineddeep
:如果源是对象,强制深度遍历,以便在深层级变更时触发回调flush
:调整回调函数的刷新时机onTrack / onTrigger
:调试侦听器的依赖(可以在里面debugger等操作)function watch<T>(
source: WatchSource<T>,
callback: WatchCallback<T>,
options?: WatchOptions
): StopHandle
这个来源可以是以下几种:
let num = ref(20)
// 基础类型 watch(要监听的响应式数据,回调(new,old))
watch(num, (newval, oldval) => {
console.log(newval, oldval)
})
使用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);
})
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
如果用到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()
上面提到的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 () {
}