vue的watch使用方法学习笔记

140 阅读4分钟

vue的watch使用方法

watch是用来监听响应式状态发生变化的,当响应式状态发生变化时,都会触发一个回调函数。

html代码:(固定)

<template> 
    <div> 
        <span>{{ count }}</span> 
        <button @click="plus" class="btn">+1</button> 
    </div> 
    <div> 
        <input v-model="form.name" type="text"> 
    </div>
</template> 

1、vue2

固定代码:

</template> 
<script> 
export default { 
    data() { 
        return { 
            count: 0, 
            form: { 
                name: "" 
            } 
        } 
    }, 
    methods: { 
        plus() { 
            this.count++ 
        } 
    }, 
} 
</script>
1. 普通监听
watch: {  
    // 普通监听
    count(newV, oldV) { 
        console.log(newV); 
    }, 
},
2. 对象内部特定属性的监听事件
watch: { 
    // 对象内部特定属性的监听事件 
    "form.name"(newV, oldV) { 
        console.log(newV); 
    }, 
},
3. 借用计算属性对"对象具体属性"的监听
computed: { 
    getPlusName() { 
        return this.form.name 
    } 
}, 
watch: { 
    // 借用计算属性对"对象具体属性"的监听
    getPlusName(newV, oldV) { 
        console.log(newV); 
    }, 
},
4. deep:true可以监听对象内部数据改变(获取不到旧值)
watch: { 
    // deep:true可以监听对象内部数据改变 
    form: { //写成对象形式,就可以跟更多的属性。不加属性与原来的写法效果是一样的。 
        handler(newV, oldV) { 
            console.log(newV); 
        }, 
        deep: true, 
        //深度侦听 
        // immediate:true 
        //立即执行(页面刚进来也会执行) 
    }, 
},
5. 可关闭的监听(获取不到旧值)
mounted() { 
    // 可关闭的监听 
    const unWatch = this.\$watch("form", (newV, oldV) => { 
        console.log(newV); 
    }, { 
        deep: true 
    }) 
    // unWatch() // 取消侦听 
}

2、vue3

  1. watch是惰性执行,也就是只有监听的值发生变化的时候才会执行,但是watchEffect不同,每次代码加载watchEffect都会执行(忽略watch第三个参数的配置,如果修改配置项也可以实现立即执行)

  2. watch需要传递监听的对象,watchEffect不需要

  3. watch只能监听响应式数据:ref定义的属性和reactive定义的对象,如果直接监听reactive定义对象中的属性是不允许的(会报警告),除非使用函数转换一下。其实就是官网上说的监听一个getter

  4. watchEffect如果监听reactive定义的对象是不起作用的,只能监听对象中的属性。

以下两种用法在行为上基本等价

watchEffect( 
    () => console.log(counter.value) 
) 
watch( 
    () => counter.value, 
    () => console.log(counter.value), 
    { immediate: true } 
)

固定代码:

<script setup> 
/** 
 * vue的watch使用方法 
 * 监视源只能是getter/effect函数、ref、响应对象或这些类型的数组 
 */ 
 import { reactive, ref, watch, watchEffect } from "vue"; 
 const count = ref(0) 
 const form = reactive({ 
     name: "" 
 }) 
 const plus = () => { 
     count.value++ 
 } 
 </script>

watch:

watch(
    () => { /* 依赖源收集函数 */ },
    () => { /* 依赖源改变时的回调函数 */ },
    () => {}
)

这里的依赖源函数只会执行一次,回调函数会在每次依赖源改变的时候触发,但是并不对回调函数进行依赖收集。也就是说,依赖源和回调函数之间并不一定要有直接关系。

watch监视, 接收三个参数

参数1: 监视的数据源

参数2: 回调函数

参数3: 额外的配置(比如深度监听)

1. getter/effect函数(监听对象的某个属性的变化)
// getter/effect函数(监听对象的某个属性的变化) 
watch(() => form.name, (newV, oldV) => { 
    console.log(newV); 
})
2. 监听单个ref
// 监听单个ref 
watch(count, (newV, oldV) => { 
    console.log(newV); 
})
3. 响应对象监听(获取不到旧值)
// 深度监听(获取不到旧值) 
watch(form, (newV, oldV) => { 
    console.log(newV.name); 
    console.log(oldV.name); 
})
4. 深度监听(获取不到旧值)
// 深度监听(获取不到旧值) 
watch(form, (newV, oldV) => { 
    console.log(newV.name); 
    console.log(oldV.name); 
}, { 
    // 深度监听:当ref的值是一个复杂数据类型,需要深度监听 
    deep: true, 
    // immediate: true //立即执行(页面刚进来也会执行) 
})
5. 多个变量监听(form获取不到旧值)
// 多个变量监听(获取不到旧值) 
watch([count, form], ([newCount, newForm], [oldCount, oldForm]) => { 
    console.log(newCount, newForm); 
    console.log(oldCount, oldForm); 
})
6. watchEffect

watchEffect 相当于将 watch 的依赖源和回调函数合并,当任何你有用到的响应式依赖更新时,该回调函数便会重新执行。不同于 watch,watchEffect 的回调函数会被立即执行(即 { immediate: true })

watchEffect(
    () => { /* 依赖源同时是回调函数 */ }
)
watchEffect(() => { 
    console.log(count.value); 
    console.log(form.name); // 只能监听对象中的属性 
})
7. 计算属性监听(补充)
// 计算属性监听 
const getCount = computed(() => { 
    return count.value 
}) 
watch(getCount, (newV, oldV) => { 
    console.log(newV); 
    console.log(oldV); 
})
8. 总结:

如果定义了reactive的数据,想去使用watch监听数据改变,则无法正确获取旧值,并且deep属性配置无效,自动强制开启了深层次监听。

如果使用 ref 初始化一个对象或者数组类型的数据,会被自动转成reactive的实现方式,生成proxy代理对象。也会变得无法正确取旧值。

用任何方式生成的数据,如果接收的变量是一个proxy代理对象,就都会导致watch这个对象时,watch回调里无法正确获取旧值。

所以在使用watch监听对象时,如果在不需要使用旧值的情况,可以正常监听对象没关系;但是如果当监听改变函数里面需要用到旧值时,只能监听 对象.xxx属性 的方式才行。

参考来源:

简书:默默无闻的小人物

知乎:Anthony Fu