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
watch是惰性执行,也就是只有监听的值发生变化的时候才会执行,但是watchEffect不同,每次代码加载watchEffect都会执行(忽略watch第三个参数的配置,如果修改配置项也可以实现立即执行)
watch需要传递监听的对象,watchEffect不需要
watch只能监听响应式数据:ref定义的属性和reactive定义的对象,如果直接监听reactive定义对象中的属性是不允许的(会报警告),除非使用函数转换一下。其实就是官网上说的监听一个getter
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属性 的方式才行。
参考来源: