watch

initWatch

组件选项对象里存在watch选项open in new window,在组件初始化状态数据的最后,将初始化watch数据。

初始化watch就是为watch选项里的每一项调用vm.$watch方法创建一个 Watcher。

需要注意的是,watchkey对应的value的形式有多种:

  • 函数
  • 组件的方法名
  • 对象,至少包含handler方法,可以有depp属性和immediate属性
  • 数组,元素是函数
function initWatch (vm: Component, watch: Object) {
  for (const key in watch) {
    const handler = watch[key]
    if (Array.isArray(handler)) {
      for (let i = 0; i < handler.length; i++) {
        createWatcher(vm, key, handler[i])
      }
    } else {
      createWatcher(vm, key, handler)
    }
  }
}

function createWatcher (
  vm: Component,
  expOrFn: string | Function,
  handler: any,
  options?: Object
) {
  if (isPlainObject(handler)) {
    options = handler
    handler = handler.handler
  }
  if (typeof handler === 'string') {
    handler = vm[handler]
  }
  return vm.$watch(expOrFn, handler, options)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

vm.$watch()

在导出Vue构造函数之前,会先调用stateMixin(Vue)为其添加一些原型方法,比如$watch

// src/core/instance/state.js
export function stateMixin (Vue: Class<Component>) {
  // ...
  Vue.prototype.$watch = function (
    expOrFn: string | Function,
    cb: any,
    options?: Object
  ): Function {
    const vm: Component = this

    // cb 可以包含在 options 里,此处处理 $watch(expOrFn, options)的情况
    if (isPlainObject(cb)) {
      return createWatcher(vm, expOrFn, cb, options)
    }
    options = options || {}
    options.user = true
    const watcher = new Watcher(vm, expOrFn, cb, options)
    if (options.immediate) {
      // 立即执行回调
      cb.call(vm, watcher.value)
    }
    // 返回取消监听函数
    return function unwatchFn () {
      watcher.teardown()
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

通过$watch创建的 Watcher 实例,其options参数的user属性为true,以区分出是用户创建的 Watcher 还是 Vue 内部创建的 Watcher。