天天看点

vue checkbox双向绑定_vue双向绑定

vue双向绑定源码解析

vue checkbox双向绑定_vue双向绑定

1、概念

  • 监听器 Observer:用来劫持并监听所有属性,如果属性发生变化,就通知订阅者;
  • 订阅器 Dep:用来收集订阅者,对监听器

    Observer

    和 订阅者

    Watcher

    进行统一管理;
  • 订阅者 Watcher:可以收到属性的变化通知并执行相应的方法,从而更新视图;
  • 解析器 Compile:可以解析每个节点的相关指令,对模板数据和订阅器进行初始化。

2、主流程相关函数(理解为代码注释)

  • initData(proxy)
  • observe
  • Observer(protoAugment/copyAugment)
  • walk
  • observeArray
  • defineReactive$$1
  • Dep
  • Watcher
  • baseCompile
/*
*主要功能是下面2个
*1、def设置proxy代理
*2、observe观察数据
*/ 
function initData (vm) {
    var data = vm.$options.data;
    data = vm._data = typeof data === 'function'
      ? getData(data, vm)
      : data || {};
    if (!isPlainObject(data)) {
      data = {};
      warn(
        'data functions should return an object:n' +
        'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
        vm
      );
    }
    var keys = Object.keys(data);
    var props = vm.$options.props;
    var methods = vm.$options.methods;
    var i = keys.length;
    while (i--) {
      var key = keys[i];
      {
        if (methods && hasOwn(methods, key)) {
          warn(
            ("Method "" + key + "" has already been defined as a data property."),
            vm
          );
        }
      }
      if (props && hasOwn(props, key)) {
        warn(
          "The data property "" + key + "" is already declared as a prop. " +
          "Use prop default value instead.",
          vm
        );
      } else if (!isReserved(key)) {
        //把data中的数据绑定到跟对象上。所有this.xxx、this.data.xxx都可访问
        proxy(vm, "_data", key);
      }
    }
    // 观察数据
    observe(data, true /* asRootData */);
  }
           
/**
   * 判断当前数据是否为对象
   * 判断__ob__属性是否存在,存在则直接引用,不存在则创建Observer实例
   * 如果是根数据则计数
   */
  function observe (value, asRootData) {    
    if (!isObject(value) || value instanceof VNode) {
      return
    }
    var ob;
    //__ob__:里面存放了该属性的观察器,也就是Observer的实例,防止重复绑定。 
    if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
      ob = value.__ob__;
    } else if (
      shouldObserve &&
      !isServerRendering() &&
      (Array.isArray(value) || isPlainObject(value)) &&
      Object.isExtensible(value) &&
      !value._isVue
    ) {
      ob = new Observer(value);
    }
    if (asRootData && ob) {
      ob.vmCount++;
    }
    return ob
  }
           
/**
   *将Observer实例绑定到目标对象的__ob__属性
   *判断当前目标对象是否为数组
   *是数组则监听数组的方法,并且为数组的每个成员尝试构建一个Observer实例(即调用observe函数)
   *是对象则响应式对象的属性
   */
  var Observer = function Observer (value) {
    this.value = value;
    this.dep = new Dep();
    this.vmCount = 0;//保存vm实例将当前对象作为根数据root $data的次数
    def(value, '__ob__', this);
    if (Array.isArray(value)) {
      if (hasProto) {
        protoAugment(value, arrayMethods);//修改数组的_proto_
      } else {
        copyAugment(value, arrayMethods, arrayKeys);//覆盖数组的方法
      }
      this.observeArray(value);//对数组类型的成员进行绑定
    } else {
      this.walk(value);//对对象类型的数据进行绑定
    }
  };
           
/**
   * 循环遍历进行数据绑定
   */
  Observer.prototype.walk = function walk (obj) {
    var keys = Object.keys(obj);
    for (var i = 0; i < keys.length; i++) {
      defineReactive$$1(obj, keys[i]);
    }
  };
           
/**
   * 循环遍历,观察数组的每一项
   */
  Observer.prototype.observeArray = function observeArray (items) {
    for (var i = 0, l = items.length; i < l; i++) {
      observe(items[i]);
    }
  };
           
/**
   * 设置getter、setter
   * 创建Dep订阅器
   */
  function defineReactive$$1 (
    obj,
    key,
    val,
    customSetter,
    shallow
  ) {
    
    var dep = new Dep();

    var property = Object.getOwnPropertyDescriptor(obj, key);
    if (property && property.configurable === false) {
      return
    }

    // cater for pre-defined getter/setters
    var getter = property && property.get;
    var setter = property && property.set;
    if ((!getter || setter) && arguments.length === 2) {
      val = obj[key];
    }

    // console.log('defineReactive$$1===>',dep,Dep,Dep.target);
    
    var childOb = !shallow && observe(val);
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: true,
      get: function reactiveGetter () {
        var value = getter ? getter.call(obj) : val;
        // 只有在有Dep.target时才说明是Vue内部依赖收集过程触发的getter
        // 那么这个时候就需要执行dep.depend(),将watcher(Dep.target的实际值)添加到dep的subs数组中
        // 对于其他时候,比如dom事件回调函数中访问这个变量导致触发的getter并不需要执行依赖收集,直接返回value即可
        if (Dep.target) {
          dep.depend();
          if (childOb) {
            //如果value是对象,那就让生成的Observer实例当中的dep也收集依赖
            childOb.dep.depend();
            if (Array.isArray(value)) {
              dependArray(value);
            }
          }
        }
        return value
      },
      set: function reactiveSetter (newVal) {
        var value = getter ? getter.call(obj) : val;
        /* eslint-disable no-self-compare */
        if (newVal === value || (newVal !== newVal && value !== value)) {
          return
        }
        /* eslint-enable no-self-compare */
        if (customSetter) {
          customSetter();
        }
        // #7981: for accessor properties without setter
        if (getter && !setter) { return }
        if (setter) {
          setter.call(obj, newVal);
        } else {
          val = newVal;
        }
        childOb = !shallow && observe(newVal);
        // 通知订阅我这个dep的watcher们:我更新了
        dep.notify();
      }
    });
  }
           
/*
*负责编译template
*1、返回AST语法树
*2、返回render函数
*3、返回静态render的数组
*/
function baseCompile (
    template,
    options
  ) {
    var ast = parse(template.trim(), options);
    if (options.optimize !== false) {
      optimize(ast, options);
    }
    var code = generate(ast, options);
    return {
      ast: ast,
      render: code.render,
      staticRenderFns: code.staticRenderFns
    }
  }
           
vue checkbox双向绑定_vue双向绑定

compile编译流程图

参考:

Vue源码学习笔记之compile​cassieran.github.io

vue checkbox双向绑定_vue双向绑定

神仙朱:【Vue原理】Compile - 白话版​zhuanlan.zhihu.com

vue checkbox双向绑定_vue双向绑定