vue数据双向绑定

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>

        <div id="app">

            <input type="text" v-model="text" /> {{text}}

        </div>

    </body>

    <script type="text/javascript">
        //          编译函数
        function compile(node, vm) {

            var reg = /\{\{(.*)\}\}/; // 来匹配{{xxx}}中的xxx

            //如果是元素节点
            if(node.nodeType === 1) {

                var attr = node.attributes;

                //解析元素节点的所有属性

                for(let i = 0; i < attr.length; i++) {

                    if(attr[i].nodeName == 'v-model') {

                        var name = attr[i].nodeValue //看看是与哪一个数据相关

                        node.addEventListener('input', function(e) { //将与其相关的数据改为最新值
                            vm[name] = e.target.value
                        })

                        node.value = vm.data[name]; //将data中的值赋予给该node

                        node.removeAttribute('v-model')

                    }

                }

            }

            //如果是文本节点

            if(node.nodeType === 3) {

                if(reg.test(node.nodeValue)) {

                    var name = RegExp.$1; //获取到匹配的字符串

                    name = name.trim();

                    //                  node.nodeValue = vm[name]; //将data中的值赋予给该node

                    new Watcher(vm, node, name) //绑定一个订阅者
                }

            }

        }

        //          在向碎片化文档中添加节点时,每个节点都处理一下

        function nodeToFragment(node, vm) {

            var fragment = document.createDocumentFragment();

            var child;

            while(child = node.firstChild) {

                compile(child, vm);

                fragment.appendChild(child);

            }

            return fragment

        }

        //          Vue构造函数     
        //      观察data中的所有属性值,注意增添了observe

        function Vue(options) {

            this.data = options.data;

            observe(this.data, this)

            var id = options.el;

            var dom = nodeToFragment(document.getElementById(id), this)

            //处理完所有节点后,重新把内容添加回去
            document.getElementById(id).appendChild(dom)

        }

        //      实现一个响应式监听属性的函数。一旦有赋新值就发生变化 

        function defineReactive(obj, key, val) {

            var dep = new Dep();

            Object.defineProperty(obj, key, {

                get: function() {

                    if(Dep.target) {

                        dep.addSub(Dep.target)

                    }

                    return val

                },
                set: function(newVal) {

                    if(newVal === val) {

                        return

                    }

                    val = newVal;

                    console.log('新值' + val);

                    //一旦更新立马通知

                    dep.notify();

                }

            })

        }

        //      实现一个观察者,对于一个实例 每一个属性值都进行观察。

        function observe(obj, vm) {

            for(let key of Object.keys(obj)) {

                defineReactive(vm, key, obj[key]);

            }

        }

        //      Watcher监听者

        function Watcher(vm, node, name) {

            Dep.target = this;

            this.vm = vm;
            this.node = node;
            this.name = name;

            this.update();

            Dep.target = null;

        }

        Watcher.prototype = {

            update() {
                this.get();
                this.node.nodeValue = this.value //更改节点内容的关键
            },
            get() {
                this.value = this.vm[this.name] //触发相应的get
            }

        }

        //      dep构造函数

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

        var vm = new Vue({

            el: 'app',

            data: {
                text: '赵刚'
            }

        })
    </script>

</html>
posted @ 2020-03-16 14:12  不服憋着  阅读(156)  评论(0编辑  收藏  举报