使用ES6的Proxy实现简单的双向绑定

ES6的Proxy对象可以用来拦截一个Object对象的属性的修改,这次我们利用它来实现一个简单的双向绑定。
废话不多说,请看代码。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>View to model</title>
</head>
<body>
    <div>
        <!-- 使用'bind-to'的属性来标记这个输入框里的值会对Model里的属性进行修改 -->
        <input bind-to="name" />
        <input bind-to="name" />
    </div>
    <!-- 使用#属性名#来把Model里的值映射到DOM中 -->
    <span>#name#</span>
    <span>#name#</span>
    <button onclick="reset()">reset</button>
    <script type="text/javascript">
        var handler = {
            // 拦截属性的设置,触发试图的更新
            set: function(target, key, value, receiver) {
                target[key] = value;
                updateView(propertyName);
                return Reflect.set(target, key, value);
            },
        };
        // 双向绑定的对象
        var model = new Proxy({}, handler);
        // 双向绑定列表
        var inputs = {},views = {};
        var all = document.all;
        // 遍历所有DOM元素
        for(var i=0,l=all.length;i<l;i++){
            // 找到所有有bind-to的输入框
            if(all[i].getAttribute('bind-to')){
                var dom = all[i];
                var propertyName = dom.getAttribute('bind-to');
                inputs[propertyName] = inputs[propertyName] ? inputs[propertyName] : [];
                views[propertyName] = views[propertyName] ? views[propertyName] : [];
                inputs[propertyName].push(dom);
                dom.addEventListener('change',function function_name(e) {
                    var propertyName = e.target.getAttribute('bind-to');
                    model[propertyName] = e.target.value;
                })
            }
            // 找到所有model驱动的页面元素
            if(all[i].innerHTML && all[i].innerHTML.length>2 &&
                all[i].innerHTML[0] == '#' &&
                all[i].innerHTML[all[i].innerHTML.length-1] == '#'){
                var propertyName = all[i].innerHTML.slice(1,all[i].innerHTML.length-1);
                inputs[propertyName] = inputs[propertyName] ? inputs[propertyName] : [];
                views[propertyName] = views[propertyName] ? views[propertyName] : [];
                views[propertyName].push(all[i]);
            }
        }
        // 更新View
        function updateView(propertyName) {console.log('update ' + propertyName);
            if(views[propertyName]){
                for(var i = 0,l = views[propertyName].length;i < l;i++){
                    views[propertyName][i].innerText = model[propertyName];
                }
            }
            if(inputs[propertyName]){
                for(var i = 0,l = inputs[propertyName].length;i < l;i++){
                    inputs[propertyName][i].value = model[propertyName];
                }
            }
        }
        function reset() {
            for(var name in model){
                model[name] = '';
            }
        }
    </script>
</body>
</html>

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注