Vue双向绑定代码实现MVVM原理

Vue三要素
响应式: 例如如何监听数据变化,其中的实现方法就是我们提到的双向绑定
模板引擎: 如何解析模板
渲染: Vue如何将监听到的数据变化和解析后的HTML进行渲染

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>
        实现vue双向绑定
    </title>
    <script>
        //1、首先实现一个整体架构(VUE类、Watcher类),订阅发布者设计模式
        //2、实现MVVM中的由M到V,把模型里面的数据绑定到视图
        //3、(1)最后实现V-M,当文本框输入文本的时候,由文本事件触发更新模型中的数据
        //   (2)同时更新相对应的视图
        //发布者
        class myVue {
            constructor(options) {
                this.$data = options.data;//获取数据
                this.$el = document.querySelector(options.el);//获取对象
                this._directive = {}//存放订阅者容器
                //改变数据 是全页面刷新还是局部刷新
                //{订阅者1,订阅者2,订阅者3,订阅者4}
                //{mytext:[订阅者1,订阅者2],mybox:[订阅者3]}
                this.Observer(this.$data);
                this.Compile(this.$el)
            }

            Observer(data) {
                for (let key in data) {
                    this._directive[key] = [];
                    let val = data[key];
                    let watch = this._directive[key];//数组
                    //this.$data里的每一个属性发生赋值 都要更新视图
                    // console.log(this._directive) this_directive含Watcher实例对象
                    Object.defineProperty(this.$data, key, {
                        get() {
                            return val;
                        },
                        set(newVal) {
                            if (newVal !== val) {
                                val = newVal;
                                //更新视图
                                // watcher实例.update
                                watch.forEach(element => {
                                    element.update();
                                });
                            }
                        }
                    })
                }
            }

            Compile(el) {

                //创建文档片段,将DOM操作放内存提高性能
                // this.$fragment = this.node2Fragment(el);
                // let nodes = this.$fragment.children;
                let nodes = el.children;
                // console.log(nodes)
                for (let i = 0; i < nodes.length; i++) {
                    let node = nodes[i];
                    if (node.children.length) {
                        this.Compile(node)
                    }
                    //怎样解析指令
                    if (node.hasAttribute('v-text')) {
                        //怎样添加订阅者
                        //首先获取订阅者名
                        let attrVal = node.getAttribute('v-text');
                        // this._directive[arrtVal].push("订阅者1"); //指令对象
                        // console.log(this._directive)
                        //订阅数据变化,绑定更新函数
                        this._directive[attrVal].push(new Watcher(node, this, attrVal, 'textContent'));
                        // console.log(this._directive)
                    }
                    if (node.hasAttribute('v-model')) {
                        let attrVal = node.getAttribute('v-model');
                        this._directive[attrVal].push(new Watcher(node, this, attrVal, 'value'));
                        node.addEventListener('input', () => {
                            // console.log("哈哈哈哈")
                            this.$data[attrVal] = node.value
                            // console.log(this.$data[attrVal])
                        })
                    }
                }
            }
            node2Fragment(el) {
                let fragment = document.createDocumentFragment()
                let child;
                while (child = el.firstChild) {
                    fragment.appendChild(child)
                }
                return fragment;
            }
        }
        //订阅者
        class Watcher {//更新视图
            constructor(el, vm, exp, attr) {
                this.el = el;
                this.vm = vm;
                this.exp = exp;
                this.attr = attr;
                this.update();//初始化视图
            }
            update() {
                // div.textContent=vue对象.$data['mytext']
                // input.value=vue对象.$data['mytext']
                this.el[this.attr] = this.vm.$data[this.exp]
            }

        }
    </script>
</head>

<body>
    <div id="app">
        <h1>双向绑定</h1>
        <div v-text="mytext">
            <div v-text="mybox"></div>
        </div>
        <div v-text="mybox"> </div>
        <input type="text" v-model="mytext">
    </div>

</body>
<script>
    var app = new myVue({
        el: '#app',
        data: {
            mytext: '青鸟软通公开课',
            mybox: 'vue实现MVVM'
        }
    });
</script>

</html>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值