• 用法
    • vm.$watch( expOrFn, callback, [options] )
  • 功能
    • 观察 Vue 实例变化的一个表达式或计算属性函数。回调函数得到的参数为新值和旧值。表达式只 接受监督的键路径。对于更复杂的表达式,用一个函数取代。
  • 参数
    • expOrFn:要监视的 $data 中的属性,可以是表达式或函数
    • callback:数据变化后执行的函数
      • 函数:回调函数
      • 对象:具有 handler 属性(字符串或者函数),如果该属性为字符串则 methods 中相应 的定义
    • options:可选的选项
      • deep:布尔类型,深度监听
      • immediate:布尔类型,是否立即执行一次回调函数

三种类型的 watcher 对象

  • 没有静态方法,因为 $watch 方法中要使用 Vue 的实例
  • Watcher 分三种:计算属性 Watcher、用户 Watcher(侦听器)、渲染 Watcher
  • 创建顺序:计算属性 Watcher、用户 Watcher(侦听器)、渲染 Watcher
  • vm.$watch()
    • src\core\instance\state.js

源码

  1. Vue.prototype.$watch = function (
  2. expOrFn: string | Function,
  3. cb: any,
  4. options?: Object
  5. ): Function {
  6. // 获取 Vue 实例 this
  7. const vm: Component = this
  8. if (isPlainObject(cb)) {
  9. // 判断如果 cb 是对象执行 createWatcher
  10. return createWatcher(vm, expOrFn, cb, options)
  11. }
  12. options = options || {}
  13. // 标记为用户 watcher
  14. options.user = true
  15. // 创建用户 watcher 对象
  16. const watcher = new Watcher(vm, expOrFn, cb, options)
  17. // 判断 immediate 如果为 true
  18. if (options.immediate) {
  19. // 立即执行一次 cb 回调,并且把当前值传入
  20. try {
  21. cb.call(vm, watcher.value)
  22. } catch (error) {
  23. handleError(error, vm, `callback for immediate watcher "${watcher.expression}"`)
  24. }
  25. }
  26. // 返回取消监听的方法
  27. return function unwatchFn () {
  28. watcher.teardown()
  29. }
  30. }

调试

  • 查看 watcher 的创建顺序
    • 计算属性的 Watcher

image.png

  • 用户 Watcher (侦听器)

image.png

  • 渲染 wacher

image.png

查看渲染 watcher 的执行过程

  1. 当数据更新,defineReactive 的 set 方法中调用 dep.notify()
  2. 调用 watcher 的 update()
  3. 调用 queueWatcher(),把 wacher 存入队列,如果已经存入,不重复添加
  4. 循环调用 flushSchedulerQueue()
    1. 通过 nextTick(),在消息循环结束之前时候调用 flushSchedulerQueue()
  5. 调用 wacher.run()
    1. 调用 wacher.get() 获取最新值
    2. 如果是渲染 wacher 结束
    3. 如果是用户 watcher,调用 this.cb()