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" );  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM