zoukankan      html  css  js  c++  java
  • Javascript实现简单的双向绑定

      双向数据绑定指的是将对象属性变化绑定到UI,或者反之。换句话说,如果我们有一个拥有name属性的user对象,当我们给user.name赋予一个新值是UI也会相应的显示新的名字。同样的,如果UI包括了一个输入字段用来输入用户名,输入一个新的值会导致user对象中的那么属性发生变化。

      双向数据绑定底层的思想非常的基本,它可以被压缩成为三个步骤:

    1. 我们需要一个方法来识别哪个UI元素被绑定了相应的属性
    2. 我们需要监视属性和UI元素的变化
    3. 我们需要将所有变化传播到绑定的对象和元素

      虽然实现的方法有很多,但是最简单也是最有效的途径是使用发布者-订阅者模式。思想很简单:我们可以使用自定义的data属性在HTML代码中指明绑定。所有绑定起来的JavaScript对象以及DOM元素都将“订阅”一个发布者对象。任何时候如果JavaScript对象或者一个HTML输入字段被侦测到发生了变化,我们将代理事件到发布者-订阅者模式,这会反过来将变化广播并传播到所有绑定的对象和元素。在这里很多人自然会想到使用jQuery,使用DOM的事件操作来监听UI变化,然后将修改对应的数据字段,再使用on来自定义事件监听数据字段的变化,将变化广播到所有绑定的对象和元素上。本文主要讨论的是使用Javascript来实现双向数据绑定,如果对jQuery实现感兴趣可的话可以参考-JavaScript实现简单的双向数据绑定

      

    这里我们只是对于之前的观察者模式的例子稍作修改,加上了对DOM元素的事件监听:

    function DataBinder(object_id){  
        // 创建一个简单的pubSub对象
        var pubSub = {
                callbacks: {},
                on: function(msg,callback) {
                    this.callbacks[msg] = this.callbacks[msg] || [];
                    this.callbacks[msg].push(callback);
                },
                publish: function(msg) {
                    this.callbacks[msg] = this.callbacks[msg] || [];
                    for (var i = 0,len = this.callbacks[msg].length; i < len; i++) {
                        this.callbacks[msg][i].apply(this,arguments);
                    };
                }
            },
    
            data_attr = "data-bind-" + object_id,
            message   = object_id + ":change",
    
            changeHandler = function(event) {
                var target    = event.target || event.srcElement, // IE8兼容
                    prop_name = target.getAttribute(data_attr);
    
                if (prop_name && prop_name !== "") {
                    pubSub.publish(message,prop_name,target.value);
                }
            };
    
        // 监听事件变化,并代理到pubSub
        if (document.addEventListener) {
            document.addEventListener("keyup",changeHandler,false);
        } else{
            // IE8使用attachEvent而不是addEventListenter
            document.attachEvent("onkeyup",changeHandler);
        };
    
        // pubSub将变化传播到所有绑定元素
        pubSub.on(message,function(event,prop_name,new_val){
            var elements = document.querySelectorAll("[" + data_attr + "=" +prop_name + "]"),
                tag_name;
            for (var i = 0,len = elements.length; i < len; i++) {
                tag_name = elements[i].tagName.toLowerCase();
    
                if (tag_name === "input" || tag_name === "textarea" || tag_name === "select") {
                    elements[i].value = new_val;
                } else{
                    elements[i].innerHTML = new_val;
                };
            };
        })
    
        return pubSub;
    }

    接着定义模型就行了:

    function User(uid) {  
        var binder = new DataBinder(uid),
          user   = {
              attribute : {},
    
              // 属性设置器使用数据绑定器pubSub来发布
              set : function(attr_name,val) {
                  this.attribute[attr_name] = val;
                  binder.publish(uid + ":change",attr_name,val,this);
              },
    
              get : function(attr_name) {
                  return this.attribute[attr_name];
              },
    
              _binder : binder
          };
    
        binder.on(uid + ":change",function(event,attr_name,new_val,initiator) {
            if (initiator !== user) {
                user.set(attr_name,new_val);
            }
        });
    
        return user;
      }

    使用起来就非常简单了,只需要新建模型,通过模型设置字段就行了

    var user = new User( 123 );  
    user.set( "name", "tsy" );  
  • 相关阅读:
    结构型设计模式(上)
    创建型设计模式(下)
    创建型设计模式(上)
    HTTP 简述
    MVC、MVP与MVVM架构模式
    PHP 部分语法(二)
    PHP 部分语法(一)
    TypeScript 学习笔记(四)
    WORD 和Uint16的区别
    extern的用法
  • 原文地址:https://www.cnblogs.com/shytong/p/5080900.html
Copyright © 2011-2022 走看看