前言

阅读本节,需要理解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几部分实现。不了解的可以先去学习这部分内容。

vue中wath的源码实现的更多相关文章

  1. Vue.js 2.0源码解析之前端渲染篇

    一.前言 Vue.js框架是目前比较火的MVVM框架之一,简单易上手的学习曲线,友好的官方文档,配套的构建工具,让Vue.js在2016大放异彩,大有赶超React之势.前不久Vue.js 2.0正式 ...

  2. 如何实现全屏遮罩(附Vue.extend和el-message源码学习)

    [Vue]如何实现全屏遮罩(附Vue.extend和el-message源码学习) 在做个人项目的时候需要做一个类似于电子相册浏览的控件,实现过程中首先要实现全局遮罩,结合自己的思路并阅读了(饿了么) ...

  3. 探秘Tomcat(一)——Myeclipse中导入Tomcat源码

    前言:有的时候自己不知道自己是井底之蛙,这并没有什么可怕的,因为你只要蜷缩在方寸之间的井里,无数次的生活轨迹无非最终归结还是一个圆形:但是可怕的是有一天你不得不从井里跳出来生活,需要重新审视井以外的生 ...

  4. Scala 深入浅出实战经典 第65讲:Scala中隐式转换内幕揭秘、最佳实践及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  5. Scala 深入浅出实战经典 第61讲:Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...

  6. Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  7. Scala 深入浅出实战经典 第48讲:Scala类型约束代码实战及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  8. [原创]在Windows和Linux中搭建PostgreSQL源码调试环境

    张文升http://ode.cnblogs.comEmail:wensheng.zhang#foxmail.com 配图太多,完整pdf下载请点这里 本文使用Xming.Putty和VMWare几款工 ...

  9. Android: 在WebView中获取网页源码

    1. 使能javascript: ? 1 webView.getSettings().setJavaScriptEnabled(true); 2. 编写本地接口 ? 1 2 3 4 5 final c ...

随机推荐

  1. Java异常抛出

    如果要在一段代码中抛出一个已检查的异常,有两个选择: 使用try-catch块处理已检查的异常. 在方法/构造函数声明中用throws子句指定. 语法 throws子句的一般语法是: 1 2 3 &l ...

  2. 转 Python - openpyxl 读写操作Excel

    Python - openpyxl 读写操作Excel   openpyxl特点   openpyxl(可读写excel表)专门处理Excel2007及以上版本产生的xlsx文件,xls和xlsx之间 ...

  3. scala调用系统-scala.sys.process使用

    简介 scala.sys.process提供了shell的和系统交互的DSL,包括执行命令, 逻辑操作, 重定向, 管道等操作. 启动流程要执行与ProcessBuilder关联的所有外部命令,sca ...

  4. ActionEnter cannot be resolved to a type

    2014-6-13 23:50:57 org.apache.catalina.core.StandardWrapperValve invoke严重: Servlet.service() for ser ...

  5. add characteristic to color

    Problem: add a new Char. name D_COI6 that the description is Injected coloration #7 (COI6) in the D_ ...

  6. 浅析php-fpm和fastcgi的关系

    先讲讲CGI吧 浏览器向web server发起请求的时候,要有url,header,params等等吧,为什么有这些数据呢,这就是CGI的事了,CGI就规定了,传哪些数据,用什么样的格式传输 web ...

  7. 浅谈HTTP与其工作流程

    一.什么是HTTP协议 HTTP协议(Hyper Text Transfer Protocol)翻译过来是超文本传输协议,也是一种restful风格的协议,在web开发和APP接口开发都很常用. HT ...

  8. Galaxy

    Galaxy 在一维坐标轴上给出n个点,第i个点坐标为\(x_i\),现在你可以任意移动k个点的,最小化它们的方差,\(n\leq 50000\). 解 感觉以前写的太乱了,补一篇可以供快速阅读的题解 ...

  9. codeforces 1A

    题目大意: 就是在一块长方形地面上铺瓷砖,然后一共要用多少块瓷砖,一块瓷砖被割开后只能用一次,输入长,宽,以及瓷砖边长,求一共需要多少块瓷砖: 基本思路: 这里有个技巧:就长来说,需要(n+k-1)/ ...

  10. ES6 数组扩展(总结)

    1.扩展运算符 将一个数组转为用逗号分隔的参数序列 console.log(1, ...[2, 3, 4], 5) // 1 2 3 4 5 2.Array.from() 将两类对象转为真正的数组 类 ...