zoukankan      html  css  js  c++  java
  • MVVM(三)数据劫持-->数据绑定

    1.数据绑定(model==>View):
           (1). 一旦更新了data中的某个属性数据, 所有界面上直接使用或间接使用了此属性的节点都会更新(更新)
       2.数据劫持
       (1). 数据劫持是vue中用来实现数据绑定的一种技术
       (2). 基本思想: 通过defineProperty()来监视data中所有属性(任意层次)数据的变化, 一旦变化就去更新界面
       3.四个重要对象
           (1). Observer
          * 用来对data所有属性数据进行劫持的构造函数
           * 给data中所有属性重新定义属性描述(get/set)
           * 为data中的每个属性创建对应的dep对象
        (2). Dep(Depend)
           * data中的每个属性(所有层次)都对应一个dep对象
           * 创建的时机:
               * 在初始化define data中各个属性时创建对应的dep对象
               * 在data中的某个属性值被设置为新的对象时
           * 对象的结构
               {
                 id, // 每个dep都有一个唯一的id
                 subs //包含n个对应watcher的数组(subscribes的简写)
               }
          * subs属性说明
             * 当一个watcher被创建时, 内部会将当前watcher对象添加到对应的dep对象的subs中
             * 当此data属性的值发生改变时, 所有subs中的watcher都会收到更新的通知, 从而最终更新对应的界面
       (3). Compile
          * 用来解析模板页面的对象的构造函数(一个实例)
          * 利用compile对象解析模板页面
          * 每解析一个表达式(非事件指令)都会创建一个对应的watcher对象, 并建立watcher与dep的关系
          * complie与watcher关系: 一对多的关系
       (4). Watcher
           * 模板中每个非事件指令或表达式都对应一个watcher对象
           * 监视当前表达式数据的变化
           * 创建的时机: 在初始化编译模板时
           * 对象的组成
             {
                 vm,  //vm对象
                 exp, //对应指令的表达式
                 cb, //当表达式所对应的数据发生改变的回调函数
                 value, //表达式当前的值
                 depIds //表达式中各级属性所对应的dep对象的集合对象
                         //属性名为dep的id, 属性值为dep
             }
         
       (5). 总结: dep与watcher的关系: 多对多
          * 一个data中的属性对应对应一个dep, 一个dep中可能包含多个watcher(模板中有几个表达式使用到了属性)
          * 模板中一个非事件表达式对应一个watcher, 一个watcher中可能包含多个dep(表达式中包含了几个data属性)
          * 数据绑定使用到2个核心技术
             * defineProperty()
             * 消息订阅与发布
    //创建监视对象
    function observe(value, vm) {
        // value必须是对象, 因为监视的是对象内部的属性
        if (!value || typeof value !== 'object') {
            return;
        }
        // 创建一个对应的观察都对象
        return new Observer(value);
    };
    // Observer构造函数
    function Observer(data) {
        // 保存data对象
        this.data = data;
        // 走起
        this.walk(data);
    }
    walk: function(data) {
            var me = this;
            // 遍历data中所有属性
            Object.keys(data).forEach(function(key) {
                // 针对指定属性进行处理
                me.convert(key, data[key]);
            });
    }
    convert: function(key, val) {
            // 对指定属性实现响应式数据绑定
            this.defineReactive(this.data, key, val);
    },
    defineReactive: function(data, key, val) {
            // 创建与当前属性对应的dep对象
            var dep = new Dep();
            // 间接递归调用实现对data中所有层次属性的劫持
            var childObj = observe(val);
            // 给data重新定义属性(添加set/get)
            Object.defineProperty(data, key, {
                enumerable: true, // 可枚举
                configurable: false, // 不能再define
                get: function() {
                    // 建立dep与watcher的关系
                    if (Dep.target) {
                        dep.depend();
                    }
                    // 返回属性值
                    return val;
                },
                set: function(newVal) {
                    if (newVal === val) {
                        return;
                    }
                    val = newVal;
                    // 新的值是object的话,进行监听
                    childObj = observe(newVal);
                    // 通过dep
                    dep.notify();
                }
            });
        }
    };
    defineReactive 建立关系 dep对象里面存放着id跟sub数组;
    data: {
          name: 'sadamu',  // dep0
          wife: { // dep1
            name: 'binbin', // dep2
            age: 18 // dep3
          }
    }
    

      

    Dep对象里面存放

    Dep{

        Id =0;

       Subs = [],表示的是name属性

    }

    Dep{

         Id =1;

        Subs = [],表示的是wife对象。里面属性递归 //subs存放的是监视对象

    }

    function Watcher(vm, exp, cb) {

      this.cb = cb;  // callback

      this.vm = vm;

      this.exp = exp;

      this.depIds = {};  // {0: d0, 1: d1, 2: d2}

      this.value = this.get();

    }

    // watcher是一个监视对象 对属性进行监视;

    1. 什么时候一个dep中关联多个watcher?

      多个指令或表达式用到了当前同一个属性  {{name}} {{name}}

    2. 什么时候一个watcher中关联多个dep?

      多层表达式的watcher对应多个dep    {{a.b.c}}

    <div id="test">

      <p>{{name}}</p>

      <p v-text="name"></p>

      <p v-text="wife.name"></p>

      <button v-on:click="update">更新</button>

    </div>

    列出:watcher与dep的对应关系

    <p>{{name}}</p>  <p v-text="name"></p> 都对name属性操作

    Name = dep{id =0;subs[2个监视对象]},因为要对视图更改多个地方

    <p v-text="wife.name"></p>  dep{id =2;subs[1个监视对象]} 只需要更改一个地方

  • 相关阅读:
    Linux定制化RPM包
    01-if条件语句之数字比较
    01-爬虫介绍
    Django的路由系统01-路由分发
    Nginx+tomcat+redis集群共享session实现负载均衡
    CAS单点登录原理
    红黑树
    B+树
    Mysql索引介绍
    B树(B-树)
  • 原文地址:https://www.cnblogs.com/love-life-insist/p/10131295.html
Copyright © 2011-2022 走看看