前言
它之所以叫侦听器呢,是因为它可以侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
大白话说呢,就是你传给 watch 侦听器一个响应式变量,然后当这个变量变化时,自动触发一个你定义的函数,啥呢,就像一个人被监控了一样,只要这个人一动,摄像头就会报警。
回忆 Vue2
先实现一个 Vue2 侦听器小例子。
<template>
<button @click="sum++">增加数值</button>
</template>
<script>
export default {
data() {
return {
sum: 1,
}
},
watch: {
// New: 新值 | Old: 老值
sum(New, Old) {
console.log(`新值:${New} ——— 老值:${Old}`)
},
}
}
</script>
可以看到,这是一个最最简单的监听示例。
切入 Vue3
在 Vue3 中呢,需要先通过 import 把 watch() 函数引过来才能用。
那么我们用 Vue3 该如何实现,刚才的小示例呢?
<template>
<button @click="sum++">增加数值</button>
</template>
<script>
import { watch, ref } from 'vue'
export default {
setup() {
// 响应式变量
const sum = ref(1)
// watch是一个函数
// 第一个参数: 要监听的响应式变量(数据源)
// 第二个参数:执行的回调函数
// 第三个参数: 配置(例如deep深度监听/immediate是否立即监听等)
watch(sum, (New, Old) => {
console.log(`新值:${New} ——— 老值:${Old}`)
})
// return
return { sum }
}
}
</script>
非常 NIce 啊,既然能监听 ref 响应式变量,那么 reactive 响应式对象能不能监听呢?我们来实现一下啊。
<template>
<button @click="sum.value++">增加数值</button>
</template>
<script>
import { watch, reactive } from 'vue'
export default {
setup() {
// 响应式变量
const sum = reactive({
value: 1
})
// watch是一个函数
// 第一个参数: 要监听的响应式变量(数据源)
// 第二个参数:执行的回调函数
// 第三个参数: 配置(例如deep深度监听/immediate是否立即监听等)
// 注意:当监听一个对象时,第一个参数数据源必须是函数且返回一个值即 "() => 对象.要监听的属性"
watch(() => sum.value, (New, Old) => {
console.log(`新值:${New} ——— 老值:${Old}`)
})
// return
return { sum }
}
}
</script>
可以看到,响应式对象也是可以监听的,注意啊,监听对象与监听普通数据在第一个参数数据源上略有差异。
监听复杂数据对象
咱们真实项目开发,哪有这么简单的数据啊,都是对象套对象,对象里再套数组,非常的复杂。
那么这种情况怎么深度监听呢?
其实很简单,只需要配置一个叫 deep 的属性为 true 即可!
<template>
<h1>值:{{ sum.car.config.isChina }}</h1>
<button @click="sum.car.config.isChina = !sum.car.config.isChina">改变数据</button>
</template>
<script>
import { watch, reactive } from 'vue'
export default {
setup() {
// 复杂嵌套响应式变量
const sum = reactive({
car: {
name: '长安汽车',
money: 15000,
config: {
color: 'black',
isChina: true,
}
}
})
// 监听复杂响应式对象
watch(() => sum.car, (New, Old) => {
console.log(`新值:${New.config.isChina} ——— 老值:${Old.config.isChina}`)
})
// return
return { sum }
}
}
</script>
咦,怎么没有监听到啊?怎么回事啊!
其实很简单,只需要配置一个叫 deep 的属性为 true 即可,大家从单词就能看出来是 “深度” 的意思啊,看看这个配置写在哪里。
watch(() => sum.car, (New, Old) => {
...
}, { deep: true })
这回再看看,没问题,监听到了!
监听多个
前面我们知道了如何监听 ref 数据,如何监听 reactive 对象数据,也知道了如何监听嵌套比较深的复杂对象数据。
如果我有两个数据需要监听怎么办?
Vue3 给你提供了多个变量监听的语法,如下代码所示。
<template>
<h2>one:{{ one }} | two: {{ two.value }}</h2>
<button @click="one++">改变 one 数据</button>
<button @click="two.value++">改变 two 数据</button>
</template>
<script>
import { watch, reactive, ref } from 'vue'
export default {
setup() {
// 变量1
const one = ref(0)
// 变量2
const two = reactive({
value: 10
})
// 监听多个变量
// 第一个参数变为数组形式,每个下标对应一个要监听的变量
// 第二个参数的函数传参改为每项数组形式,每个数组对应新旧值的参数
watch(
[ one, () => two.value ],
( [oneNew, oneOld], [twoNew, twoOld] ) => {
console.log(`one: ${oneNew}(新) ——— ${twoNew}(旧)`)
console.log(`two: ${oneOld}(新) ——— ${twoOld}(旧)`)
console.warn('——————————————————————————————————————————————')
})
// return
return { one, two }
}
}
</script>
可以看到啊,相比于之前的 Vue2 写法,这种写法虽然会随着监听的变量增多而增加复杂度,但是整体的话聚集在一起,很好维护。
有些看不太懂这个新旧值的一个对应关系,我们来分析一下啊。
咱们看变量 one
,它的新旧值对应的是 oneNew
/ twoNew
,而 tow
则对应的新旧值是 oneOld
、 twoOld
,这个对应关系看起来有点反人类啊,大家仔细观察规律,多看多写几遍就明白了。
监听器是惰性的
在 Vue2/3 中 watch 是惰性的,啥意思呢,就是它比较懒,那怎么个懒法呢,就是当你写好 watch 监听后,它不会主动触发监听函数,而是当你数据改变时才触发。
如下示例:
<template>
<button @click="sum++">增加数值</button>
</template>
<script>
import { watch, ref } from 'vue'
export default {
setup() {
// 响应式变量
const sum = ref(1)
// 懒惰的玩意
watch(sum, () => {
console.log('我触发啦!')
})
// return
return { sum }
}
}
</script>
运行,可以看到,我刷新页面,它并不会触发监听函数,这就叫做惰性,控制台没有任何输出。
注意啊,重点来了,假如我就想初次进入页面的时候就让它执行,让它勤奋点,有什么办法能做到吗?
能!并且非常简单,只需要一个配置项即可。
我们来改造一下。
<template>
<button @click="sum++">增加数值</button>
</template>
<script>
import { watch, ref } from 'vue'
export default {
setup() {
// 响应式变量
const sum = ref(1)
// 勤奋了
watch(sum, () => {
console.log('我触发啦!')
}, { immediate: true })
// return
return { sum }
}
}
</script>
当我刷新页面的时候,马上就触发了,果然勤奋了!
停止监听
最后呢,我们来说一下 Vue3 独有的停止监听,啥意思呢,就是咱们可以手动控制 watch 是否继续对一个变量进行监听,随时让 watch 放弃对某个变量的后续监听。
在 Vue2 中是没有停止监听的功能,你回忆一下,当你写好监听后,watch 是不是会永远等待?是不是根本不存在关掉这一说?
Vue3 之所以提供了停止监听的方法,这是因为持续监听会占用内部资源,很可能咱们某个变量都不需要后续持续监听了,但又没有办法关掉。
说了这么多,我们来手动实现一下。
<template>
<button @click="sum++">增加数值</button>
<button @click="stop">停止监听</button>
</template>
<script>
import { watch, ref } from 'vue'
export default {
setup() {
// 响应式变量
const sum = ref(1)
// 想要支持停止监听,必须将watch结果用一个变量进行接收
const result = watch(sum, () => {
console.log('我触发啦!')
})
// 停止监听
const stop = () => {
// 写上接收的变量名即可
result()
}
// return
return { sum, stop }
}
}
</script>
很神奇。
SEO
Vue3官方文档,vue3.js watch 侦听器官方教程文档,vue3—watch侦听器总结太到位了,vue3 watch侦听器,详解Vue3中侦听器watch的使用教程,VUE3中watch监听使用实例详解,vue3—watch侦听器总结太到位了,Vue3侦听器watch,详解Vue3中侦听器watch的使用教程,Vue3 我对watch侦听器的理解,VUE3 中的 Watch 详解,Vue 3 响应式侦听与计算属性,Vue3 watch 和 watchEffect 侦听器,vue3.0中的watch侦听器实例详解,Vue3.xwatch函数—侦听器,Vue3 setup中watch监听器的使用,Vue选项:watch侦听器,一文搞懂Vue3中watch和watchEffect区别和用法,vue3 setup中watch监听的使用方法,Vue3 - watch 侦听器(超详细使用教程)。