vue mvvm原理与简单实现 -- 上篇

Object.defineProperty介绍--
    let obj = {};
    Object.defineProperty(obj,'school',{
        configurable : true, // 属性能否被删除
        //writable : true, // 属性能否被修改
        enumerable : true, // 属性能否枚举
        //value : 'zfpx', // 设置属性值

        set : function(value){
            console.log(value); // obj.school赋值时, 调用set() 方法
        },
        get : function(){
            return 'zfpx'; // 获取 obj.school 的值时,调用 get() 方法
        }
    })
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<body>
<div id="app">
    <p>{{a.a}}</p>
    <div>{{b}}
<div>{{b}}</div>
    </div>
</div>
</body>
<!-- mvvm 双向数据绑定
vue 数据劫持+发布订阅模式
不兼容低版本 Object.defineProperty -->
<script>

    (function(window,document){
        function ZF(options = {}){
            this.$options = options; // 将所有的属性挂载在 $options 上
            let data = this._data = this.$options.data;
            this.observe(data);
            for(let key in data){ // 把data属性通过Object.defineProperty的方式定义属性
                // 数据代理
                // this代理了this._data
                Object.defineProperty(this,key,{
                    enumerable : true, // 可枚举
                    get: function(){
                        return this._data[key];
                    },
                    set: function(newVal){ // 更改值的时候
                        this._data[key] = newVal;
                    }
                });
            }
            this.Compile(options.el,this);
        }
        // 编译
        ZF.prototype.Compile = function(el,vm){
            vm.$el = document.querySelector(el);
            let fragment = document.createDocumentFragment();
            while(child = vm.$el.firstChild){  // 将app中的内容 移入内存中
                fragment.appendChild(child);
            }
            // 循环每一层
            Array.from(fragment.childNodes).forEach(function(node){

                let text = node.textContent;
                let reg = /\{\{(.*)\}\}/;
    
                if( reg.test(text)){
                    let arr = RegExp.$1.split('.');
                    let val = vm;
                    console.log(node.childNodes)
                    console.log(arr)
                    arr.forEach(function(k){
                        val = val[k];
                    })
                    // 替换
                    node.textContent = text.replace(/\{\{(.*)\}\}/,val)
                }
                //node.textContent.textContent(12)

            })
            vm.$el.appendChild(fragment);
        }
        // 观察对象给对象增加ObjectDefineProperty;
        ZF.prototype.observe = function(data){
            //console.log(data)
            return new Observe(data);
            
        }
        function Observe(data){
            for(let key in data){ // 把data属性通过Object.defineProperty的方式定义属性
                let val = data[key];
                // 递归
                if(typeof val === 'object'){
                    Observe(val);
                }
                Object.defineProperty(data,key,{
                    enumerable : true, // 可枚举
                    get: function(){
                        return val;
                    },
                    // 数据劫持
                    set: function(newVal){ // 更改值的时候
                        if(newVal === val){
                            return;
                        }
                        if(typeof newVal === 'object'){
                            Observe(newVal);
                        }
                        val = newVal; //
                    }
                });
            }
        }
        window.ZF = ZF;

    })(window,document);

    let zf = new ZF({
        el : "#app",
        data : {a:{a:'是a'},b:'是b'},
    })


    
</script>
</html>

 

posted @ 2020-01-27 14:27  cl94  阅读(168)  评论(0编辑  收藏  举报