美文网首页
对象代理,双向绑定的简单实现

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

作者: D_R_M | 来源:发表于2019-03-14 10:08 被阅读0次
    <!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>
    
    

    相关文章

      网友评论

          本文标题:对象代理,双向绑定的简单实现

          本文链接:https://www.haomeiwen.com/subject/uhsolqtx.html