使用defineProperty进行双向绑定的原理

<!DOCTYPE html>
<html>

<head>
    <title>defineProperty</title>
</head>

<body>
    name:<input type="text" id="name">
    age:<input type="number" id="age">
    <br />
    <br />
    name:<span id="namep"></span>
    <br />
    age:<span id="agep"></span>

    <script type="text/javascript">
    function Obj() {

    }
    Obj.prototype.data = {
        name: "mvvm",
        age: 18
    }

    let dataObj = new Obj();

    Object.keys(dataObj.data).forEach(key => {
        Object.defineProperty(dataObj, key, {
            get: function() {
                return dataObj[key];
            },
            set: function(newValue) {
                document.getElementById(`${key}p`).innerHTML = newValue;
                dataObj.data[key] = newValue;
            }
        });
    });

    document.getElementById("name").addEventListener('keyup', function(e) {
        dataObj["name"] = e.target.value;
    });

    document.getElementById("age").addEventListener('keyup', function(e) {
        dataObj["age"] = e.target.value;
    });
    </script>
</body>

</html>

 

<!DOCTYPE html>
<html>

<head>
    <title>KOA</title>
</head>

<body>
    <input type="text" k-value="value" id="input" />
    <div k-text="value" id="el"></div>
    <script type="text/javascript">
    /**基本思路是使用Object.defineProperty对数据对象做属性get和set的监听,当有数据读取和赋值操作时则调用节点的指令,这样使用最通用的=等号赋值就可以了。*/
    var elems = [document.getElementById('el'), document.getElementById('input')];
    var data = {
        value: "hello"
    };

    var command = {
        text: function(str) {
            this.innerHTML = str;
        },
        value: function(str) {
            this.setAttribute('value', str);
        }
    }

    let scan = function() {
        for (let i = 0, len = elems.length; i < len; i++) {
            let elem = elems[i];
            elem.command = [];
            for (let j = 0, len1 = elem.attributes.length; j < len1; j++) {
                let attr = elem.attributes[j];
                if (attr.nodeName.indexOf('k-') >= 0) {
                    //调用属性指令
                    command[attr.nodeName.slice(2)].call(elem, data[attr.nodeValue]);
                    elem.command.push(attr.nodeName.slice(2));
                }
            }
        }
    }

    let bValue;

    /**
     * 定义属性劫持
     */
    let defineGetAndSet = function(obj, propName) {
        try {
            Object.defineProperty(obj, propName, {
                get: function() {
                    return bValue;
                },
                set: function(newValue) {
                    bValue = newValue;
                    scan();
                },
                enumerable: true,
                configurable: true
            });
        } catch (err) {
            console.log("browser not supported");
        }
    }

    //初始化数据
    scan();

    defineGetAndSet(data, 'value');

    if (document.addEventListener) {
        elems[1].addEventListener('keyup', function(e) {
            data.value = e.target.value;
        }, false);
    } else {
        elems[1].attachEvent('onkeyup', function(e) {
            data.value = e.target.value;
        }, false);
    }

    setTimeout(function(){
        data.value = 'hello kruce';
    }, 2000)
    </script>
</body>

</html>

 

 

posted @ 2019-03-18 18:50  MakeCoder  阅读(508)  评论(0编辑  收藏  举报