侦听数据变化也是组件里的一项重要工作,比如侦听路由变化、侦听参数变化等等。
Vue 3 在保留原来的 watch 功能之外,还新增了一个 watchEffect 帮助更简单的进行侦听。
watch
 在 Vue 3 ,新版的 watch 和 Vue 2 的旧版写法对比,在使用方式上变化非常大!
 回顾 Vue 2
 在 Vue 2 是这样用的,和 data 、 methods 都在同级配置:
export default {
  data() {
    return {
      // ...
    }
  },
  // 注意这里,放在 `data` 、 `methods` 同个级别
  watch: {
    // ...
  },
  methods: {
    // ...
  },
}
 
并且类型繁多,选项式 API 的类型如下:
watch: { [key: string]: string | Function | Object | Array}
 
联合类型过多,意味着用法复杂,下面是个很好的例子,虽然出自 官网 的用法介绍,但过于繁多的用法也反映出来对初学者不太友好,初次接触可能会觉得一头雾水:
export default {
  data() {
    return {
      a: 1,
      b: 2,
      c: {
        d: 4,
      },
      e: 5,
      f: 6,
    }
  },
  watch: {
    // 侦听顶级 Property
    a(val, oldVal) {
      console.log(`new: ${val}, old: ${oldVal}`)
    },
    // 字符串方法名
    b: 'someMethod',
    // 该回调会在任何被侦听的对象的 Property 改变时被调用,不论其被嵌套多深
    c: {
      handler(val, oldVal) {
        console.log('c changed')
      },
      deep: true,
    },
    // 侦听单个嵌套 Property
    'c.d': function (val, oldVal) {
      // do something
    },
    // 该回调将会在侦听开始之后被立即调用
    e: {
      handler(val, oldVal) {
        console.log('e changed')
      },
      immediate: true,
    },
    // 可以传入回调数组,它们会被逐一调用
    f: [
      'handle1',
      function handle2(val, oldVal) {
        console.log('handle2 triggered')
      },
      {
        handler: function handle3(val, oldVal) {
          console.log('handle3 triggered')
        },
        /* ... */
      },
    ],
  },
  methods: {
    someMethod() {
      console.log('b changed')
    },
    handle1() {
      console.log('handle 1 triggered')
    },
  },
}
 
当然肯定也会有开发者会觉得这样选择多是个好事,选择适合自己的就好,但笔者还是认为这种写法对于初学者来说不是那么友好,有些过于复杂化,如果一个用法可以适应各种各样的场景,岂不是更妙?
TIP
另外需要注意的是,不能使用箭头函数来定义 Watcher 函数 (例如 searchQuery: newValue => this.updateAutocomplete(newValue) )。
因为箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向组件实例, this.updateAutocomplete 将是 undefined 。
 
Vue 2 也可以通过 this.$watch() 这个 API 的用法来实现对某个数据的侦听,它接受三个参数: source 、 callback 和 options 。
export default {
  data() {
    return {
      a: 1,
    }
  },
  // 生命周期钩子
  mounted() {
    this.$watch('a', (newVal, oldVal) => {
      // ...
    })
  },
}
 
由于 this.$watch 的用法和 Vue 3 比较接近,所以这里不做过多的回顾,请直接看 了解 Vue 3 部分。
了解 Vue 3
 在 Vue 3 的组合式 API 写法, watch 是一个可以接受 3 个参数的函数(保留了 Vue 2 的 this.$watch 这种用法),在使用层面上简单了很多。
import { watch } from 'vue'
// 一个用法走天下
watch(
  source, // 必传,要侦听的数据源
  callback // 必传,侦听到变化后要执行的回调函数
  // options // 可选,一些侦听选项
)
 
下面的内容都基于 Vue 3 的组合式 API 用法展开讲解。
 API 的 TS 类型
 在了解用法之前,先对它的 TS 类型声明做一个简单的了解, watch 作为组合式 API ,根据使用方式有两种类型声明:
 1.基础用法的 TS 类型,详见 基础用法 部分
// watch 部分的 TS 类型
// ...
export declare function watch<T, Immediate extends Readonly<boolean> = false>(
  source: WatchSource<T>,
  cb: WatchCallback<T, Immediate extends true ? T | undefined : T>,
  options?: WatchOptions<Immediate>
): WatchStopHandle
// ...
 
2.批量侦听的 TS 类型,详见 批量侦听 部分
// watch 部分的 TS 类型
// ...
export declare function watch<
  T extends MultiWatchSources,
  Immediate extends Readonly<boolean> = false
>(
  sources: [...T],
  cb: WatchCallback<MapSources<T, false>, MapSources<T, Immediate>>,
  options?: WatchOptions<Immediate>
): WatchStopHandle
// MultiWatchSources 是一个数组
declare type MultiWatchSources = (WatchSource<unknown> | object)[]
// ...
 
但是不管是基础用法还是批量侦听,可以看到这个 API 都是接受三个入参:
 












![[附源码]Python计算机毕业设计SSM基于旅游服务平台(程序+LW)](https://img-blog.csdnimg.cn/9065ba7b472b4fd88ff50972910f3388.png)






