Vue3 - watch 侦听器(保姆级详细使用教程)

什么是watch侦听器

它之所以叫侦听器,是因为它可以侦听一个或多个响应式数据源数据,并再数据源变化时调用所给的回调函数。
就是你传给watch侦听器一个响应式变量,然后当这个变量变化时,自动触发一个你定义的函数,
就像一个人被监控了一样,只要这个人一动,摄像头就会报警

回忆Vue2

先实现一个 Vue2 侦听器小例子。

<template>
  <button @click="sum++">增加数值</button>
</template>

<script setup>
export default {
  data() {
    return {
      sum: 1,
    }
  },

  watch: {
    // New: 新值 | Old: 老值
    sum(New, Old) {
      console.log(`新值:${New} ——— 老值:${Old}`)
    },
  }
}
</script>

Vue3 - watch 侦听器(保姆级详细使用教程)_第1张图片
可以看到,这是一个最最简单的监听示例。

切入Vue3

  1. 基础概念
    在Vue3中,watch特性进行了一些改变和优化。与computed不同,watch通常用于监听数据的变化,并执行一些副作用,例如 发送网络请求、更新DOM等。本文将介绍Vue3中watch特性。
  2. Watch的基本用法
watch(source, callback, options?)
其中,source表示要监听的数据,可以是一个响应式的数据对象、一个计算属性或一个方法的返回值;callback表示当数据发生变化时
要执行的回调函数;options表示watch的一些配置选项,例如immediate、deep、flush等。

Vue中实现的实例 单个ref的值

<template>
  <button @click="sum++">增加数值</button>
</template>
<template>
  <button @click="sum++">增加数值</button>
</template>

<script setup lang="ts">
import { watch, ref } from 'vue'
const sum=1;
// New: 新值 | Old: 老值
watch(sum,(New, Old)=>{
	console.log(`新值:${New} ——— 老值:${Old}`)
})
</script>

Vue3 - watch 侦听器(保姆级详细使用教程)_第2张图片
非常 NIce 啊,既然能监听 ref 响应式变量,那么 reactive 响应式对象能不能监听呢?我们来实现一下啊。

<template>
  <button @click="sum.value++">增加数值</button>
</template>

<script setup lang="ts">
	import { watch,reactive} from 'vue'
    // 响应式变量
    const sum = reactive({
      value: 1
    })
    // watch是一个函数
    // 第一个参数: 要监听的响应式变量(数据源)
    // 第二个参数:执行的回调函数
    // 第三个参数: 配置(例如deep深度监听/immediate是否立即监听等)
    // 注意:当监听一个对象时,第一个参数数据源必须是函数且返回一个值即 "() => 对象.要监听的属性"
    watch(() => sum.value, (New, Old) => {
      console.log(`新值:${New} ——— 老值:${Old}`)
    })
</script>

Vue3 - watch 侦听器(保姆级详细使用教程)_第3张图片
可以看到,响应式对象也是可以监听的,注意啊,监听对象与监听普通数据在第一个参数数据源上略有差异。

监听复杂数据对象

复杂数据是指对象套对象,对象里再套数组等等,非常复杂。
那么这种情况怎么深度监听呢?
其实很简单,只需要配置一个叫 deep 的属性为 true 即可!
<template>
  <h1>值:{{ sum.car.config.isChina }}</h1>
  <button @click="sum.car.config.isChina = !sum.car.config.isChina">改变数据</button>
</template>

<script setup lang="ts">
	import { watch, ref ,reactive} from 'vue'
    // 复杂嵌套响应式变量
    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}`)
    }, { deep: true })
</script>

监听多个ref的值,采用数组形式

Vue3 给你提供了多个变量监听的语法,如下代码所示。
<template>
  <h2>one:{{ one }} | two: {{ two.value }}</h2>
  <button @click="one++">改变 one 数据</button>
  <button @click="two.value++">改变 two 数据</button>
</template>

<script setup lang="ts">
	import { watch, ref ,reactive} from 'vue'
	// 变量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('——————————————————————————————————————————————')
	})
</script>

Vue3 - watch 侦听器(保姆级详细使用教程)_第4张图片
可以看到啊,相比于之前的 Vue2 写法,这种写法虽然会随着监听的变量增多而增加复杂度,但是整体的话聚集在一起,很好维护。

有些看不太懂这个新旧值的一个对应关系,我们来分析一下啊。
Vue3 - watch 侦听器(保姆级详细使用教程)_第5张图片
咱们看变量 one,它的新旧值对应的是 oneNew / twoNew,而 tow 则对应的新旧值是 oneOld 、 twoOld,这个对应关系看起来有点反人类啊,大家仔细观察规律,多看多写几遍就明白了

监听器是惰性的

在 Vue2/3 中 watch 是惰性的,啥意思呢,就是它比较懒,那怎么个懒法呢,就是当你写好 watch 监听后,
它不会主动触发监听函数,而是当你数据改变时才触发。
如下示例:

<template>
  <button @click="sum++">增加数值</button>
</template>

<script setup lang="ts">
	import { watch,reactive} from 'vue'
    // 响应式变量
    const sum = ref(1)
    // 懒惰的玩意
    watch(sum, () => {
      console.log('我触发啦!')
    })
</script>

运行,可以看到,我刷新页面,它并不会触发监听函数,这就叫做惰性,控制台没有任何输出。

注意啊,重点来了,假如我就想初次进入页面的时候就让它执行,让它勤奋点,有什么办法能做到吗?

能!并且非常简单,只需要一个配置项即可。

我们来改造一下。

<template>
  <button @click="sum++">增加数值</button>
</template>

<script setup lang="ts">
	import { watch,ref} from 'vue'

    // 响应式变量
    const sum = ref(1)

    // 勤奋了
    watch(sum, () => {
      console.log('我触发啦!')
    }, { immediate: true })

</script>

在这里插入图片描述
当我刷新页面的时候,马上就触发了,果然勤奋了!

Watch的高级用法

  1. immediate
    immediate选项可以用于指定watch在组件创建时立即执行一次回调函数,而不必等待数据的变化。例如:
import { reactive, watch } from 'vue'

const state = reactive({
  count: 0
})

watch(
  () => state.count,
  (newVal, oldVal) => {
    console.log(`count值从${oldVal}变成了${newVal}`)
  },
  { immediate: true }
)

在上面的例子中,我们使用immediate选项将watch的回调函数在组件创建时立即执行了一次,输出了初始值。当state.count变化时,watch的回调函数还会被再次执行。
2. deep

deep选项可以用于深度监听一个对象或数组的变化。当我们监听一个对象或数组时,默认情况下只会监听对象或数组的引用变化,
而不会监听其内部数据的变化。如果我们需要深度监听对象或数组内部数据的变化,可以使用deep选项。例如:
import { reactive, watch } from 'vue'

const state = reactive({
  todos: [
    { id: 1, text: '学习Vue3', done: false },
    { id: 2, text: '学习React', done: false },
    { id: 3, text: '学习Angular', done: true }
  ]
})

watch(
  () => state.todos,
  (newVal, oldVal) => {
    console.log(`todos数组发生了变化`)
  },
  { deep: true }
)

state.todos[0].done = true // 输出:todos数组发生了变化

注意:当我们使用deep选项时,watch的性能会受到一定的影响,因为Vue需要对对象或数组进行递归遍历。因此,只有在必要的情况下才应该使用deep选项。
3. flush
flush选项可以用于指定watch的回调函数在何时执行。例如:

sync:同步模式下执行
pre:在数据变化之前执行回调函数
post:在数据变化之后执行回调函数,但是需要等待所有依赖项都更新后才执行
import { reactive, watch } from 'vue'
const state = reactive({
  count: 0
})
watch(
  () => state.count,
  (newVal, oldVal) => {
    console.log(`count值从${oldVal}变成了${newVal}`)
  },
  { flush: 'sync' }
)
state.count++ // 输出:count值从0变成了1

在上面的例子中,我们使用flush选项将watch的回调函数在同步模式下执行了,这意味着watch的回调函数会在数据变化之后立即执行。当我们执行state.count++时,会触发count的变化,从而执行watch的回调函数并输出变化的值

Watch的性能优化

在使用watch时,为了优化性能,我们可以采取以下一些方法:

  1. 使用computed替代watch

    在有些情况下,如果我们只是想监听一个值的变化,并在变化时执行一些操作,我们可以使用computed代替watch。
    computed可以自动缓存计算的结果,只有在它的依赖项变化时才会重新计算,因此可以提高一定的性能。例如:
    
import { reactive, computed } from 'vue'

const state = reactive({
  count: 0
})

const doubleCount = computed(() => {
  return state.count * 2
})

console.log(doubleCount.value) // 输出:0

state.count++

console.log(doubleCount.value) // 输出:2

2.使用throttle和debounce控制回调函数的执行频率

在有些情况下,我们可能会频繁地监听一个值的变化,并在变化时执行一些操作。如果回调函数执行的太频繁,会影响性能。
为了避免这种情况,我们可以使用throttle和debounce控制回调函数的执行频率。
throttle和debounce都是用于控制函数执行频率的工具函数。
throttle可以用于控制函数在一定时间内只能执行一次,而debounce可以用于控制函数在一定时间内不会连续执行。
例如:
import { reactive, watch } from 'vue'
import { throttle } from 'lodash-es'

const state = reactive({
  count: 0
})

watch(
  () => state.count,
  throttle((newVal, oldVal) => {
    console.log(`count值从${oldVal}变成了${newVal}`)
  }, 1000)
)

state.count++


停止监听

最后呢,我们来说一下 Vue3 独有的停止监听,啥意思呢,就是咱们可以手动控制 watch 是否继续对
一个变量进行监听,随时让 watch 放弃对某个变量的后续监听。

在 Vue2 中是没有停止监听的功能,你回忆一下,当你写好监听后,watch 是不是会永远等待?是不是根本不存在关掉这一说?

Vue3 之所以提供了停止监听的方法,这是因为持续监听会占用内部资源,很可能咱们某个变量都不需要后续持续监听了,但又没有办法关掉。

说了这么多,我们来手动实现一下。

<template>
  <button @click="sum++">增加数值</button>
  <button @click="stop">停止监听</button>
</template>

<script setup lang="ts">
	import { watch,ref} from 'vue'

    
    // 响应式变量
    const sum = ref(1)

    // 想要支持停止监听,必须将watch结果用一个变量进行接收
    const result = watch(sum, () => {
      console.log('我触发啦!')
    })
    // 停止监听
    const stop = () => {
      // 写上接收的变量名即可
      result()
    }

</script>

一个具有注脚的文本。[^1]
转载自以下链接:
原文链接:https://blog.csdn.net/to_the_Future/article/details/129391411,
原文链接:http://www.inspinia.net/a/31602.html?action=onClick,
原文链接:https://blog.csdn.net/weixin_44198965/article/details/127863123
————————————————

你可能感兴趣的:(vue3+ts+vite,vue.js,javascript,前端,前端框架)