zoukankan      html  css  js  c++  java
  • vue数据双向绑定原理-observer


    ​​
    1)vue数据双向绑定原理-observer
    ​2)vue数据双向绑定原理-wather​
    3)vue数据双向绑定原理-解析器Complie

    vue数据双向绑定原理, 和简单的实现

    去他喵的底层原理,框架内核, 老夫写代码只用Jquery 。

    个人觉得,不论是否 是长期与之交集, 还是应该看下核心的东西. 多多了解高人是如何实现的 , 这样才能学到更多的知识, 才能成长进步.  倘若某天被人问起, 某种框架 内裤,其实现原理, 那么只能是一脸懵逼了..

    实现数据绑定的做法有大致如下几种:

    -发布者-订阅者模式(backbone.js)

    -脏值检查(angular.js)

    -数据劫持(vue.js)

    vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty() 来劫持各个属性的setter , getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

    假如写过C# winform 自定义控件的, 我想更好理解之后的逻辑和实现原理

    在C# 中 当控件的某个属性发生了变化, 就刷新视图

    priveate int  a ;
    public  int A
    {
       get { return a; }
       set { if(a!=value){a = value;Invalidate();} }
    }
    # 当a的值发生变化,就重绘视图
    

    再来看看Object.defineProperty(obj,prop,descriptor)  方法

    Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

    obj 需要被操作的目标对象

    prop 目标对象需要定义或修改的属性的名称。

    descriptor 将被定义或修改的属性的描述符

    descriptor =>
    configurable 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false。

    enumerable 当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false。 数据描述符同时具有以下可选键值:

    value 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。

    writable 当且仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变。默认为 false。 存取描述符同时具有以下可选键值:

    get 一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined。

    set 一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。

    先来实现一个简单数据劫持

    var A = {}
    var a = ''
    Object.defineProperty(A, 'a', {
        set: function (value) {
            a = value
        },
        get: function () {
            return 'My name is ' + a
        }
    })
    
    A.a = 'chuchur'
    console.log(A.a) // My name is chuchur
    

    不光是这么简单, 来看下vue 的代码

    <div id="app">
        <input type="text" v-model="word">
        <p>{{word}}</p>
        <button v-on:click="sayHi">change model</button>
    </div>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                word: 'Hello World!'
            },
            methods: {
                sayHi: function() {
                    this.word = 'Hi, everybody!';
                }
            }
        });
    </script>
    

    已经实现的简单的数据劫持, 那么有多个属性,就要实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,还需要一个订阅器Dep来收集这些属性的变动来通知订阅者

    元素节点的v-model, v-on:click ,就需要实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数

    最后实现一个订阅者Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图

    大概的流程图如下:

    实现Observer

    将需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter 这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化

    // observe
    function observe(data) {
        if (data && typeof data === 'object') {
            // 取出所有属性遍历
            Object.keys(data).forEach(function (key) {
                defineReactive(data, key, data[key]);
            });
        }
        return
    };
    
    function defineReactive(data, key, val) {
        observe(val); // 监听子属性
        Object.defineProperty(data, key, {
            enumerable: true, // 可枚举
            configurable: false, // 不能再define
            get: function () {
                return val;
            },
            set: function (value) {
                console.log('监听到值变化了: ', val, '==>', value);
                val = value;
            }
        });
    }
    var A = {
        fristName: 'chuchur',
        age: 29
    }
    observe(A)
    
    A.fristName = 'nana' //监听到值变化了:  chuchur ==> nana
    A.age = 30 //监听到值变化了:  29 ==> 30
    

    这样就实现了多个属性的监听,接下来就是实现订阅器Dep, 当这些属性变化的时候,触发通知notify,告诉执行订阅者 执行更新函数

    //Dep
    function Dep() {
        this.subs = [];
    };
    Dep.prototype = {
        addSub: function(sub) {
            this.subs.push(sub);
        },
        notify: function() {
            this.subs.forEach(function(sub) {
                sub.update();
            });
        }
    };
    

    把订阅器植入到监听器里

    function defineReactive(data, key, val) {
        var dep = new Dep()
        observe(val);  //监听子属性
        Object.defineProperty(data, key, {​
            set: function (value) {​
                dep.notify() //发出通知,我被改变了
            }
        });
    }
    

    至此,简陋的 监听器就实现完成了, 接下来继续完成 Watcher.

  • 相关阅读:
    [转]The Regular Expression Object Model
    [转]Blue Prism Interview Questions and Answers
    [转]Date and String Function in BluePrism
    [转]Have a query in Blue prism coding stage and collection stage.
    [转]Blue Prism VBO Cheat Sheet
    [转]秒杀系统优化方案之缓存、队列、锁设计思路
    [转]How to: Create a Report Server Database (Reporting Services Configuration)
    [转]Python in Visual Studio Code
    [转]How to Download and Setup Blue Prism
    [转]Blue Prism Architecture
  • 原文地址:https://www.cnblogs.com/chuchur/p/9396991.html
Copyright © 2011-2022 走看看