watch API 使用,至少需要指定两个参数: sourc
e 和 callback
,其中 callback 被明确指定只能为函数,所以不同是用方式的差别其实只在 source 。
接下来我们看一下 vue3 侦听器的基本使用:
<template> <div> <h1>watch 侦听器</h1> <el-input v-model="num" /> <br> <br> <el-button type="primary" @click="num++">num + 1</el-button> </div> </template> <script> import { watch, ref } from 'vue' export default { setup() { const num = ref(1) watch(num, (newVal, oldVal) => { console.log("新值:", newVal, " 旧值:", oldVal) }) return { num, } } } </script> <style scoped> .el-input { width: 100px; } </style>
上面的代码是页面上有一个数字,点击按钮一下,数字加一,然后侦听器侦听数字的变化,打印出侦听的最新值和老值。
OK。上边的案例就是 vue3 侦听器的简单案例,侦听器和计算属性一样,可以创建多个侦听器,这个是没有问题的,案例就不写了,和上一节讲的声明多个计算属性是一致的。如果有不明白的可以看一下我的上一篇博客。
上边我们说过这么一句话,watch API 至少需要指定两个参数: source 和 callback。通过上边的案例我们看到了, 确实是两个,source 是监听的数据,callback 是监听回调,那为啥说是至少呢?
对的,因为他还有第三个参数 —— 配置对象。
在 vue2 里面,我们打开页面就像让侦听器立即执行,而不是在第一次数据改变的时候才开始执行,这时候有一个参数叫 immediate
,设置了这个参数,创建第一次就执行,所以说呢,vue3 同样可以使用。
上面的案例刷新执行的时候发现,在点击按钮之前,也就是 num 创建的时候,侦听器是没有执行的,所以说呢,加上 immediate 参数,就可以让侦听器立即执行操作。
<template> <div> <h1>watch 侦听器</h1> <el-input v-model="num" /> <br> <br> <el-button type="primary" @click="num++">num + 1</el-button> </div> </template> <script> import { watch, ref } from 'vue' export default { setup() { const num = ref(1) watch(num, (newVal, oldVal) => { console.log("新值:", newVal, " 旧值:", oldVal) }, { immediate: true }) return { num, } } } </script> <style scoped> .el-input { width: 100px; } </style>
我们看到,刷新完页面,还没有点击按钮让 num 加一的,控制台就有数据打印了,为什么呢?就是因为我们加了 immediate 为 true,让侦听器立即执行。控制台输出最新的值也就是我们初始化的值1,老的值没有,所以输出了 undefined。
上面说了侦听器侦听单个数据,他也可以用来侦听对象的变化。
<template> <div> <h1>watch 侦听器</h1> <el-input v-model="num.age" /> <br> <br> <el-button type="primary" @click="num.age++">num + 1</el-button> </div> </template> <script> import { watch, ref, reactive } from 'vue' export default { setup() { const num = reactive({ name: '我是????????.', age: 10 }) watch(num, (newVal, oldVal) => { console.log(newVal, oldVal) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
比如说上面代码,我们侦听 num 这个对象的变化。
看效果我们发下,在监听整个 reactive 响应式对象的时候,确实当里面的属性值发生改变了之后可以被侦听器检测到,但是 newVal 和 oldVal 的值都是新的,默认是10,点击之后,新值是 11 很正常,但是老值不应该是 10 吗?为什么这里老值和新值一样也是 11 呢?
这个不需要疑问哈,如果监听整个 reactive 数据的话,只能回调到最新的值,获取不到老的值。
那问题来喽,我就修改 age 属性,我就要获取 age 老的值怎么办?其实我们只需要监听 num 下面的 age 就可以了,先看下面的代码哈。
<template> <div> <h1>watch 侦听器</h1> <el-input v-model="num.age" /> <br> <br> <el-button type="primary" @click="num.age++">num + 1</el-button> </div> </template> <script> import { watch, ref, reactive } from 'vue' export default { setup() { const num = reactive({ name: '我是????????.', age: 10 }) watch(num.age, (newVal, oldVal) => { console.log(newVal, oldVal) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
我们监听对象直接是 num.age, 监听年龄属性值,保存看一下效果。
刷新结果我们可以看到哈,我们啥都没干,侦听器直接报了一个警告给我们,啥意思呢,其实不能直接这样监听。
当我们需要监听某个对象属性的时候,我们不能直接对象点属性的方式进行监听,需要传入一个 getter 方法,也就是箭头函数进行监听,下面的代码是正确方式哈。
<template> <div> <h1>watch 侦听器</h1> <el-input v-model="num.age" /> <br> <br> <el-button type="primary" @click="num.age++">num + 1</el-button> </div> </template> <script> import { watch, ref, reactive } from 'vue' export default { setup() { const num = reactive({ name: '我是????????.', age: 10 }) watch(() => num.age, (newVal, oldVal) => { console.log(newVal, oldVal) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
OK,保存刷新,我们发现,侦听器已经不报错了,而且我们点击按钮让 age 加一的时候,可以顺利的监听到 age 的变化,并且回调出最新值和上一次的值。
通过箭头函数,我们就可以实现对象属性的监听。
很多人说,vue2 在监听对象的时候需要对侦听器设置深度侦听,为什么 vue3 这个不需要呢?因为他监听响应式对象,默认就是深度监听。但是,如果监听的是深度嵌套对象或数组中的 property 变化时,仍然需要 deep 选项设置为 true。
看下面的案例,我们监听深层嵌套的 time 属性值。其实我觉得没大必要,不使用箭头函数其实可以。但是还是写一下吧。
<template> <div> <h1>watch 侦听器</h1> <el-input v-model="num.todo.time" /> <br> <br> <el-button type="primary" @click="num.todo.time ++">num.todo.time + 1</el-button> </div> </template> <script> import { watch, ref, reactive, computed, } from 'vue' export default { setup() { const num = reactive({ name: '我是????????.', age: 10, todo: { name: '弹吉他', time: 1 } }) watch(() => num, (newVal, oldVal) => { console.log(newVal.todo.time, oldVal.todo.time) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
保存代码刷新,发现点击之后没有监听到。
这个时候就可以加上 deep 深度监听。
<template> <div> <h1>watch 侦听器</h1> <el-input v-model="num.todo.time" /> <br> <br> <el-button type="primary" @click="num.todo.time ++">num.todo.time + 1</el-button> </div> </template> <script> import { watch, ref, reactive, computed, } from 'vue' export default { setup() { const num = reactive({ name: '我是????????.', age: 10, todo: { name: '弹吉他', time: 1 } }) watch(() => num, (newVal, oldVal) => { console.log(newVal.todo.time, oldVal.todo.time) }, { deep: true }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
加上深度监听 { deep:true }
我们可以看到打印出信息来了,其实我觉得这个方法有点多余,但是万一用到呢是吧?啊哈哈哈哈,自己根据情况选择使用吧。
但是有一点要注意哈!深度侦听需要遍历被侦听对象中的所有嵌套的 属性,当用于大型数据结构时,开销很大。因此请只在必要时才使用它,并且要留意性能。
本来不打算说了,但是逼逼赖赖这么久了,稍微简单提一下吧。
比如说我们需要监听多个参数,假设两个哈,然后每个参数监听到之后,执行的逻辑是不一样的,我们可以创建多个侦听器来分别监听,不写全部代码了,只写关键代码了哈。
// 第一个 watch(num, (newVal, oldVal) => { console.log(newVal, oldVal) }) // 第二个 watch(()=> boy.age, (newVal, oldVal) => { console.log(newVal, oldVal) })
这个的意思就是无论是 num 改变还是 boy.age 改变,我执行的代码都是一样的。看下面案例:
<template> <div> <h1>watch 侦听器</h1> <el-input v-model="num.name" /> <el-input v-model="num.age" /> <br> <br> <el-button type="primary" @click="num.todo.time ++">num.todo.time + 1</el-button> </div> </template> <script> import { watch, ref, reactive, computed, } from 'vue' export default { setup() { const num = reactive({ name: '我是????????.', age: 10, todo: { name: '弹吉他', time: 1 } }) watch([() => num.name, () => num.age], (newVal, oldVal) => { console.log(newVal, oldVal) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
保存刷新页面,修改 name 和 age 的值。
上面我们把数据源以数组的方式传入,返回的回调参数,新值和旧值都是以数组的方式返回,新值旧值的数组内顺序就是我们数据源传入的顺序,都能看出来哈。
如果你不想让他返回数组你可以这样改一下,其实都差不多,了解一下,根据实际情况选择性使用就行。
<template> <div> <h1>watch 侦听器</h1> <el-input v-model="num.name" /> <el-input v-model="num.age" /> <br> <br> <el-button type="primary" @click="num.todo.time ++">num.todo.time + 1</el-button> </div> </template> <script> import { watch, ref, reactive, computed, } from 'vue' export default { setup() { const num = reactive({ name: '我是????????.', age: 10, todo: { name: '弹吉他', time: 1 } }) watch([() => num.name, () => num.age], ([newName, newAge], [oldName, oldAge]) => { console.log(newName, newAge, oldName, oldAge) }) return { num } } } </script> <style scoped> .el-input { width: 100px; } </style>
保存刷新查看一下效果。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
长按识别二维码并关注微信
更方便到期提醒、手机管理