双向数据绑定原理

1. 利用Object.defineProperty

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script>
        // 1、首先实现一个整体的架构(包括MVVM类或VUE类、Watcher)
        // 2、然后实现MVVM中的M到V,把模型里面的数据渲染到视图
        // 3、监听界面输入框数据变化,更新M,同时同步到V

        // 发布者
        class Vue{
            constructor(options){
                this.options = options;
                this.$data = options.data;
                this.$el = document.querySelector(options.el);
                this._directive = {}; // 容器 存放订阅者信息 key为data的key value为数组
                
                this.Observer(this.$data);
                this.Compile(this.$el);
            }
            // 劫持数据
            Observer(data){
                for(let key in data) {
                    this._directive[key] = [];

                    let watch = this._directive[key];
                    let val = data[key];

                    Object.defineProperty(this.$data,key,{
                        set:function(newVal){
                            console.log(newVal);
                            if(newVal !== val){
                                val = newVal;
                                watch.forEach(element => {
                                    element.update();
                                });
                            }
                        },
                        get:function(){
                            return val;
                        }
                    })
                }
            }

            // 解析命令
            Compile(el){
                let nodes = el.children; 
                for (let node of nodes) {
                    if(node.children.length){
                        this.Compile(node);
                    }
                
                    if(node.hasAttribute('v-text')){
                        let attrVal = node.getAttribute('v-text');
                        this._directive[attrVal].push(new Watcher(node, this, attrVal, 'innerHTML'));
                    }

                    if(node.hasAttribute('v-model')){
                        let attrVal = node.getAttribute('v-model');
                        this._directive[attrVal].push(new Watcher(node, this, attrVal, 'value'));
                        // 监听输入框数据
                        node.addEventListener("input",()=>{
                            this.$data[attrVal] = node.value;
                        });

                    }
                }
            }
        }

        // 订阅者 更新界面数据
        class Watcher{
            constructor(el, vm, exp, attr){
                this.el = el;
                this.vm = vm;
                this.exp = exp;
                this.attr = attr;
                this.update();
            }
            update(){
                this.el[this.attr] = this.vm.$data[this.exp];
            }
        }
    </script>
</head>
<body>
    <div id='app'>
        <h1>数据响应式</h1>
        <div>
            <div v-text='myText' id = 'test'></div>
            <div v-text='myBox'></div>
            <input type="text" v-model='myText'>
            <input type="text" v-model='myBox'>
        </div>
    </div>
</body>
<script>
    const app = new Vue({
        el:'#app',
        data:{
            myText:'myText',
            myBox:'myBox'
        },
    })
</script>
</html>

2. 利用Proxy

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div id='app'>
        <h3 id='paragraph'></h3>
        <input type="text" id='input'>
    </div>
</body>
<script>
    const paragraph = document.querySelector('#paragraph');
    const input = document.querySelector('#input');

    const data = {
        text:"hello world"
    }

    const handler = {
        set: function(target, prop, value){
            if(prop=='text'){
                target[prop] = value;
                paragraph.innerHTML = value;
                input.value = value;
                return true;
            }
            return false;
        }
    }

    const myText = new Proxy(data,handler);
    
    input.addEventListener('input',function(e){
        myText.text = e.target.value;
    })

    myText.text = data.text;

</script>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值