vue2的 watch的理解(7)

首先看下watch所支持的用法,不然你不知道支持哪些用法。

var vm = new Vue({
  data: {
    a: 1,
    b: 2,
    c: 3,
    d: 4,
    e: {
      f: {
        g: 5
      }
    }
  },
  watch: {
    //平时相信都是这种写法居多  函数
    a: function (val, oldVal) {
      console.log('new: %s, old: %s', val, oldVal)
    },
    // 方法名  字符串,  我是没用过这种。。。冷门,关键源码里面有
    b: 'someMethod',
    

  // 深度 watcher  对象
    c: {
      handler: function (val, oldVal) { /* ... */ },
      deep: true
    },
    // 该回调将会在侦听开始之后被立即调用  也是对象
    d: {
      handler: function (val, oldVal) { /* ... */ },
      immediate: true
    },

    // 数组
    e: [
      function handle1 (val, oldVal) { /* ... */ },
      function handle2 (val, oldVal) { /* ... */ }
    ],
    
    // watch vm.e.f's value: {g: 5}
    'e.f': function (val, oldVal) { /* ... */ }
  }
})
vm.a = 2 // => new: 2, old: 1

 所以watch支持的写法有:数组、函数、对象、字符串

this.$watch('name', newName => {...})还可以有这种写法,说明vue2的时候就有vue3的影子了类似hooks那种用法,下面源码有介绍。

function initState(vm) {  // 初始化所有状态时
  vm._watchers = []  // 当前实例watcher集合
  const opts = vm.$options  // 合并后的属性
  
  ... // 其他状态初始化
  
  if(opts.watch) {  // 如果有定义watch属性
    initWatch(vm, opts.watch)  // 执行初始化方法
  }
}

---------------------------------------------------------

function initWatch (vm, watch) {  // 初始化方法
  for (const key in watch) {  // 遍历watch内多个监听属性
    const handler = watch[key]  // 每一个监听属性的值
    if (Array.isArray(handler)) {  // 如果该项的值为数组
      for (let i = 0; i < handler.length; i++) {
        createWatcher(vm, key, handler[i])  // 将每一项使用watcher包装
      }
    } else {
      createWatcher(vm, key, handler) // 不是数组直接使用watcher
    }
  }
}

---------------------------------------------------------

function createWatcher (vm, expOrFn, handler, options) {
  if (isPlainObject(handler)) { // 如果是对象,参数移位
    options = handler  
    handler = handler.handler
  }
  if (typeof handler === 'string') {  // 如果是字符串,表示为方法名
    handler = vm[handler]  // 获取methods内的方法
  }
  return vm.$watch(expOrFn, handler, options)  // 封装
}

总结:

1.首先在new vue初始化阶段时候, 会在initState函数里面先判断是否有定义watch,有的话就执行initWatch

2.使用for in 遍历watch里面的每个key,这里比较有意思的是:watch支持数组函数,平时我们写法都是单个对象方式定义。如果传了数组函数就遍历该数组,调用createWatcher(vm, key, handler)函数。

3.createWatcher首先对 hanlder 的类型做判断,这里面只有2种判断,对象+字符串

        3.1如果传的是对象就拿到它最终的回调函数。

        3.2如果是字符串就是方法名,会直接映射到vm上面赋值给handler。

        3.3 如果是函数就不用理会,直接vm.$watch

最后调用 vm.$watch(keyOrFn, handler, options) 函数,$watch 是 Vue 原型上的方法,它是在执行 stateMixin 的时候定义的

接下来看下$watch的内部实现:

Vue.prototype.$watch = function(expOrFn, cb, options = {}) {
  const vm = this
  if (isPlainObject(cb)) {  // 如果cb是对象,当手动创建监听属性时
                           
    return createWatcher(vm, expOrFn, cb, options)
  }
  
  options.user = true  // user-watcher的标志位,传入Watcher类中
  const watcher = new Watcher(vm, expOrFn, cb, options)  // 实例化user-watcher
  
  if (options.immediate) {  // 立即执行
    cb.call(vm, watcher.value)  // 以当前值立即执行一次回调函数
  }  // watcher.value为实例化后返回的值
  
  return function unwatchFn () {  // 返回一个函数,执行取消监听
    watcher.teardown()
  }
}

---------------------------------------------------------------
总结下上面源码发现,this.$watch第二个参数可以传对象

export default {
  data() {
    return {
      name: 'cc'
    }  
  },
  created() {
    第一种传对象:
         let obj={
                  handler: function (val, oldVal) { /* ... */ },
                  deep: true
               }
    this.unwatch1 = this.$watch('name', obj)

    第二种传函数:
    this.unwatch = this.$watch('name', newName => {...})
    this.unwatch()  // 取消监听   最后会返回一个函数取消
  }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值