美文网首页
Vue双向绑定原理

Vue双向绑定原理

作者: 来了啊小老弟 | 来源:发表于2019-10-08 15:24 被阅读0次
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <div id="app"></div>
    </body>
    </html>
    <script type="text/javascript">
        var temObserable;
        // 观察者
        function Observer (){
            this.observables = []
        }
        Observer.prototype.notify = function(){
            for(var i=0;i<this.observables.length;i++){
                this.observables[i].update()
            }
        }
        Observer.prototype.subscribe = function(){
            this.observables.push(temObserable)
        }
        //可观察对象 具备事件触发的能力
        function Observable(node,propName,data){
            this.$node = node;
            this.$propName= propName;
            this.$data = data;
        }
        Observable.prototype.update = function(){
            if(this.$node.nodeType === 1){
                this.$node.value = this.$data[this.$propName]
            } else if(this.$node.nodeType === 3){
                this.$node.nodeValue = this.$data[this.$propName]
            }
        }
        //  MVVM 是一个构造函数,接受一个options对象,存起来
        function MVVM(options){
            this.$el = options.el;
            this.$options = options;
            this.$data = options.data;
            this.$template = options.template;
            this.$$data = this.$data();//数据对象
    
            //监视属性,遍历对象
            this.init();
        }
    
        MVVM.prototype.init = function(){
            this.defineReactive(this.$$data,this.$$data.text); //{text:'abc'}
            this.compiler(this.$template,this.$$data)
        };
        MVVM.prototype.compiler = function(tempstr,data){
            //将tempstr插入到app中
            var box = document.querySelector(this.$el);
            box.innerHTML = tempstr
            //分析box 获取到其中的标记
            var nodes = box.children[0].childNodes;
            //正则匹配
            var regexText = /.*\{\{(.*)\}\}.*/;
            var regexV = /^v-(.*)$/
            // var i=0;i<nodes.length;i++
            for(var i = nodes.length-1;i>=0;i--){
                //判断Nodetype ===3 文本标签,===1 input标签
                var node= nodes[i]
                if(node.nodeType === 3){
                    var result = regexText.exec(node.nodeValue);
                    if(result){
                        //获取结果与this.$$data匹配 this.$$data[XXX]
                        //触发获取
                        this.textMatch(result[1].trim(), node);  //text
                    }
                }else if(node.nodeType === 1){
                    //获取元素的属性名称
                    var nodeAttrs = node.attributes;
                    for(var j=0;j<nodeAttrs.length;j++){
                        console.log(nodeAttrs[j])
                        var attr = nodeAttrs[j];
                        var result = regexV.exec(attr.name)
                        if(result){
                            console.log(attr.name,attr.value,"被匹配了",result)
                            this.redirective[result[1]](attr.value, node, this.$$data)
                        }
                    }
                }
            }
        }
        MVVM.prototype.redirective = {
            model:function(propName, node, data){
                temObserable = new Observable(node,propName,data)
                //给元素添加事件和给一个初始值
                node.value = data[propName];
                node.addEventListener('input',function(e){
                    data[propName] = e.target.value
                })
            }
        }
        MVVM.prototype.textMatch = function(propName, node){
            //1创建存储信息的行为  可观察对象
            //2将其挂载全局
            //3触发get函数,并从全局中取出1
            temObserable = new Observable(node,propName,this.$$data)
            node.nodeValue = this.$$data[propName]
        }
        MVVM.prototype.defineReactive = function(obj,value){
            for(var key in obj){
                //创建观察者
                var Observers = new Observer()
                Object.defineProperty(obj,key,{
                    set:function(v){
                        //更新观察者中的所有可观察对象中的节点数据
                        value = v;
                        console.log('set触发')
                        Observers.notify()
                    },
                    get:function(){
                        //为节点初始化的时候触发,将当前的节点关联上可观察对象,并加入到观察者中
                        console.log('get触发')
                        if(temObserable){
                            Observers.subscribe();
                            temObserable = null
                        }
                        return value
                    }
                })
            }
        }
        var vm = new MVVM({
            el:"#app",
            data(){
                return {
                    text:"abc"
                }
            },
            template:"<div><input type='text' v-model='text'/>{{text}}</div>"
        })
    </script>
    

    相关文章

      网友评论

          本文标题:Vue双向绑定原理

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