前言

阅读本节,需要理解vue的数据驱动原理。

看这样一段代码

new Vue({
    data: {
        msg: 'hello',
        say: 'hello world',
    },
    watch: {
        msg(newVal) {
            this.say = newVal + ' world';
        }
    }
})

vue的data包括2个属性msg和say,watch中监听msg并更新say的值。

源码实现

1. new Vue

function Vue (options) {
  if ("development" !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword');
  }
  this._init(options);
}

new Vue会执行原型上的_init方法, _init方法中hi调用 initState,这个方法会初始化所有状态相关内容

2. initWatch

initStatus会判断如果我们定义了watch则执行initWatch

function initWatch (vm, watch) {
  for (var key in watch) {
    var handler = watch[key];
    if (Array.isArray(handler)) {
      for (var i = 0; i < handler.length; i++) {
        createWatcher(vm, key, handler[i]);
      }
    } else {  
      createWatcher(vm, key, handler);
    }
  }
}

这段代码意思是如果watch声明了一个数组,则遍历数组并调用createWatcher,如果不是数组就直接调用createWatcher传递过去。这就证明,watch我们可以声明多个处理函数。

3. createWatcher

createWatcher主要工作是处理传入值,传入不同的值,做不同的兼容处理

function createWatcher (
  vm,
  expOrFn,
  handler,
  options
) {
 // 如果handler是对象,则获取handler下面的handler属性当作watch的执行函数
  if (isPlainObject(handler)) {
    options = handler;
    handler = handler.handler;
  }
// 如果handler是字符串,则获取vue原型上的方法
  if (typeof handler === 'string') {
    handler = vm[handler];
  }
// 调用vue原型上的$watch
  return vm.$watch(expOrFn, handler, options)
}

通过以上我们可以看出,watch定义有很多种类型,比如:

new Vue({
    watch: {
       // 字符串
        test1: 'handleTest',
        // 对象
        test2: {
            handler(newVal) {
                // ....
            }
        }
    },
    methods: {
        handleTest(newVal) {
            // ...
        }
    }
})

4. vm.$watch

Vue.prototype.$watch = function (
    expOrFn,
    cb,
    options
) {
    var vm = this;
    if (isPlainObject(cb)) {
        return createWatcher(vm, expOrFn, cb, options)
    }
    options = options || {};
    options.user = true;
    // new 一个Watcher实例
    var watcher = new Watcher(vm, expOrFn, cb, options);
    if (options.immediate) {
        cb.call(vm, watcher.value);
    }
    return function unwatchFn() {
        watcher.teardown();
    }
};

通过以上代码可以看出,watch的创建最终其实是vue内部创建了一个Watcher实例。那么Watcher是vue中很重要的一部分,它是数据驱动不可缺少的一部分。

接下来大概讲一下new Watcher的功能是什么样的。

5. new Watcher

vue在拿到了要监听的属性和属性更新执行的函数后,new Watcher创建一个Watcher。

Watcher是订阅者,它“监听更新行为”并执行更新函数。

为什么双引号?其实不是它在监听。以最初的代码为例更新步骤如下:

1. vue内部new Watcher创建一个Watcher实例

2. Watcher实例创建时会将自己添加到data.msg的Observer中(数据驱动原理知识)

3. 当我们改变msg值时,msg Observer会通知所有被观察者,其中就包括以上Watcher。(数据驱动原理知识)

4. Watcher触发更新并且执行回调,因此执行了我们声明的函数。

完结

watch的实现很简单,这里需要vue的数据驱动原理,由Object.defileProperty、Dep、Watcher几部分实现。不了解的可以先去学习这部分内容。

最新文章

  1. [转]了解SQL Server锁争用:NOLOCK 和 ROWLOCK 的秘密_Mr_Indigo的空间
  2. 准确率(Accuracy), 精确率(Precision), 召回率(Recall)和F1-Measure
  3. linux下SVN忽略文件/文件夹的方法
  4. 配置VS使用winteracter
  5. 个性二维码开源专题&lt;基础篇&gt;
  6. GeoServer+MySQL安装及配置过程
  7. cf455a(简单dp)
  8. DrawIndexedPrimitive参数详解
  9. Hadoop集群(第8期)_HDFS初探之旅
  10. 博客不再更新,已转移到自己的小站iwenku.net
  11. 转:PHP超时处理全面总结
  12. 由于权限不足而无法读取配置文件出现的HTTP 500.19解决办法
  13. Web2py也有意思的
  14. 详细解析 RxAndroid 的使用方式
  15. Photoshop理论:另外一种角度看图层混合模式
  16. Python教程(1.2)——Python交互模式
  17. Oracle解锁表笔记
  18. #194 sequence(搜索+动态规划+主席树)
  19. CentOS6安装Zabbix4.0
  20. Remove menucool tooltip trial version

热门文章

  1. Spring快速开启计划任务
  2. Linux下设置Core文件生成路径及文件名
  3. ionic3.0 alipay-base插件移除后会添加多余的链接文件在nodes-modules中,导致再安装其他插件或移除插件时报错问题
  4. 手机作为蓝牙音频源连接到Linux时,如何通过音量键调节传入的音量大小
  5. Sed的查,删,增,改
  6. ubuntu批量转换所有子文件夹下图片文件格式
  7. 从 Server Timing Header 看服务器是如何处理请求的
  8. Vuex的管理员Module(实战篇)
  9. 前后端分离进行权限管理之后端API返回菜单及权限信息(三)
  10. ansible如何用root用户运行普通用户授权