资讯专栏INFORMATION COLUMN

剖析Vue3中侦听器watch的使用教程

3403771864 / 601人阅读

  上一节我们简单的介绍了一下vue3 项目中的计算属性,这一节我们继续 vue3 的基础知识讲解。

  这一节我们来说 vue3 的侦听器。

  学过 vue2 的小伙伴们肯定学习过侦听器,主要是用来监听页面数据或者是路由的变化,来执行相应的操作,在 vue3里面呢,也有侦听器的用法,功能基本一样,换汤不换药的东西。 侦听器是常用的 Vue API 之一,它用于监听一个数据并在数据变动时做一些自定义逻辑,本文将先列举侦听器在 Vue 中的使用方式,然后再分析源码讲述为什么可以这样使用、以及侦听器的实现原理。下面我们稍微说一下侦听器。

  watch 侦听器使用。

  watch API 使用,至少需要指定两个参数:source 和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>

  上面的代码是页面上有一个数字,点击按钮一下,数字加一,然后侦听器侦听数字的变化,打印出侦听的最新值和老值。

1.png

  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>

2.png

  我们看到,刷新完页面,还没有点击按钮让 num 加一的,控制台就有数据打印了,为什么呢?就是因为我们加了 immediate 为 true,让侦听器立即执行。控制台输出最新的值也就是我们初始化的值1,老的值没有,所以输出了 undefined。

  侦听器监听 reactive

  上面说了侦听器侦听单个数据,他也可以用来侦听对象的变化。

  <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 这个对象的变化。

3.png

  看效果我们发下,在监听整个 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, 监听年龄属性值,保存看一下效果。

4.png

  刷新结果我们可以看到哈,我们啥都没干,侦听器直接报了一个警告给我们,啥意思呢,其实不能直接这样监听。

  当我们需要监听某个对象属性的时候,我们不能直接对象点属性的方式进行监听,需要传入一个 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 的变化,并且回调出最新值和上一次的值。

5.png

  通过箭头函数,我们就可以实现对象属性的监听。

  很多人说,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>

  保存代码刷新,发现点击之后没有监听到。

6.png

  这个时候就可以加上 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 }

7.png

  我们可以看到打印出信息来了,其实我觉得这个方法有点多余,但是万一用到呢是吧?啊哈哈哈哈,自己根据情况选择使用吧。

  但是有一点要注意哈!深度侦听需要遍历被侦听对象中的所有嵌套的 属性,当用于大型数据结构时,开销很大。因此请只在必要时才使用它,并且要留意性能。

  监听多个参数执行各自逻辑

  本来不打算说了,但是逼逼赖赖这么久了,稍微简单提一下吧。

  比如说我们需要监听多个参数,假设两个哈,然后每个参数监听到之后,执行的逻辑是不一样的,我们可以创建多个侦听器来分别监听,不写全部代码了,只写关键代码了哈。

  // 第一个
  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 的值。

8.png

  上面我们把数据源以数组的方式传入,返回的回调参数,新值和旧值都是以数组的方式返回,新值旧值的数组内顺序就是我们数据源传入的顺序,都能看出来哈。

  如果你不想让他返回数组你可以这样改一下,其实都差不多,了解一下,根据实际情况选择性使用就行。

  <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>

  保存刷新查看一下效果。

9.png

  有关Vue3中侦听器watch的使用教程内容已全部讲述完毕,欢迎关注后续更多精彩内容。


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/130352.html

相关文章

  • 关于Vue2一些值得推荐文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    sutaking 评论0 收藏0
  • 关于Vue2一些值得推荐文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    khs1994 评论0 收藏0
  • 针对vue wtach一次详细剖析

    摘要:提问深度与非深度的区别对象与数组与的区别的一个特点是,最初绑定的时候是不会执行的,要等到改变时才执行监听计算。为一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象适用场景一个数据影响多个数据。 提问 1.深度watch与非深度watch的区别;2.watch对象与数组;3.watch与computed的区别; immediate FullNa...

    crossoverJie 评论0 收藏0
  • 面向未来编程(Future-Oriented Programming),建设未来 Vue 生态

    摘要:状态管理社区当前最流行的状态管理方案分别是单向数据流的和基于的。目前的现状主要是由于并没有将其底层的曝光出来。是一个开源项目,完全兼容的,拥簇面向未来编程,致力于加速未来生态圈的建设。 概要 Vue 的作者尤雨溪最近公布了 3.0 版本最重要的 RFC Vue Function-based API。在 React 推出 Hooks 后不久,Vue 社区也迎来了自己的组件逻辑复用机制。 ...

    J4ck_Chan 评论0 收藏0

发表评论

0条评论

3403771864

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<