对象代理,双向绑定的简单实现

2019-03-14  本文已影响0人  D_R_M
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>MVVM</title>
</head>
<body>
<div id="app">
    <div>{{msg}},{{name}},{{msg}}</div>
    <span>span 后 -》 {{name}}</span>
    <div>{{msg}}
        <div>
            <div></div>
        </div>
    </div>
    {{name}}
    <input type="text" c-model="name"/>
</div>
<script>
    ;(function (window,document) {
        var MVVM = function(obj){
            if(!(this instanceof MVVM)) return new MVVM(obj);
            this.$el = document.querySelector(obj.el);
            Object.defineProperty(this,'$data',{
                value:obj.data,
                enumerable: false,
                configurable: true
            })
            Object.keys(this.$data).forEach(function(item){
                this.$data[item]=new ViewModel(this.$data[item],this);//双向绑定
                Object.defineProperty(this,item,{//对象代理
                    enumerable: true,
                    configurable: true,
                    set:function(val) {
                        this.$data[item].setVal(val);
                    },
                    get:function() {
                        return this.$data[item].getVal();
                    }
                })
            }.bind(this));
            this.init(this.$el);
        }
        MVVM.prototype.init=function(elment){
            var el = elment;
            var fragment = document.createDocumentFragment();
            var childNode;
            while (childNode = el.firstChild){
                fragment.appendChild(childNode);
            }
            this.replace(fragment.childNodes);
            Object.keys(this.$data).forEach((item)=>{
                this.$data[item].updates();
            })
            el.appendChild(fragment);
        }
        MVVM.prototype.replace =function(fragmentContent){
            Array.prototype.slice.call(fragmentContent).forEach(item=>{
                if(item.nodeType === 1){
                    Array.from(item.attributes).forEach(attr=>{
                        if(attr.name.indexOf('c-') >= 0){
                            this.$data[attr.value].bindNode(item);
                            item.removeAttribute(attr.name);
                            item.addEventListener('input',function (e) {
                                this.$data[attr.value].setVal(e.target.value);
                            }.bind(this))
                        }
                    });
                    if(item.childNodes.length>0){
                        this.replace(item.childNodes);
                    }
                }else if(item.nodeType === 3){
                    var reg = /\{\{([^\}]+)\}\}/g;
                    if(reg.test(item.textContent)){
                        item.textContent.replace(reg,function () {
                            item.bindc=item.textContent;
                            this.$data[arguments[1]].bindNode(item);
                        }.bind(this));
                    }
                }
            })
        }
        var ViewModel =function(data,mvvm) {
            this.data = data;
            this.nodes = [];
            this.mvvm = mvvm;
        }
        ViewModel.prototype.bindNode=function (node) {
            this.nodes.push(node);
        }
        ViewModel.prototype.updates = function () {
            this.nodes.forEach(item=>{
                if(item.nodeType === 1 && item.nodeName =='INPUT'){
                    item.value = this.data;
                }else{
                    var reg = /\{\{([^\}]+)\}\}/g;
                    item.textContent = item.bindc.replace(reg,function(){
                    return this.mvvm.$data[arguments[1]].data
                    }.bind(this))
                }
            })
        }
        ViewModel.prototype.setVal = function (newVal) {
            if(newVal !== this.data){//值有改变  才做 修改
                this.data = newVal;
                this.updates();
            }
        }
        ViewModel.prototype.getVal = function () {
                return this.data;
        }
        window.MVVM = MVVM;
    })(window,document);

    var mv = MVVM({
        el:'#app',
        data:{
            msg:'我是msg',
            name:'我是name'
        }
    });
</script>
</body>
</html>

上一篇下一篇

猜你喜欢

热点阅读