实现数据的双向绑定最直接的方式就是PubSub模式。

(1)当model发生变化时,触发Model change事件,然后通过相应事件处理函数更新界面。--'model-update-event'

(2)当界面更新时,触发UI change事件,然后通过相应事件处理函数更新Model,以及绑定在Model上的其他界面控件。--'ui-update-event'

 

对于所有支持双向绑定的页面控件来说,当控件的'值'发生变化时,会触发'ui-update-event'事件。(这里只处理包含't-binding'属性的控件)。

当Model订阅了(监听)'ui-update-event',相应的界面改动会更新Model。

大致的原理为:  

function DataBinder(){
  //发布/订阅封装
  var pubSub={    
    handlers:{},
    on:function(event,callback){
      if(!this.handlers[event]){
        this.handlers[event]=[];
      }
      this.handlers[event].push(callback);
    },
    publish:function(event){
      var handler=this.handlers[event];
      if(handler){
        for(var i=0;i<handler.length;i++){
          handler[i]();
        }
      }
    }
  };

  changeHandler=fucntion(e){
    var target=e.target||e.srcElement;
    var prop_name=event.getAttribute('t-binding');
    if(prop_name && prop_name!==''){
      pubSub.publish('ui-update-event',prop_name,target.value);
    };
  };
  //监听事件变化(这里监听keyup和change事件),并代理到pubSub上。
  if(document.addEventListener){
    document.addEventListener('keyup',changeHandler,false);
    document.addEventListener('change',changeHandler,false);
  }else{
    //兼容ie8  
    document.attachEvent('keyup',changeHandler);
    document.attarEvent('change',changeHandler);
  };
  //pubSub将变化传播到所有绑定元素上。
  pubSub.on('model-update-event',function(propName,propValue){
    var eles=document.querySelectorAll('[t-binding="'+propName+'"]');
    for(var i=0;i<eles.length;i++){
      var eleType=eles[i].tagName.toLowerCase(); 
    //更新UI界面上元素的内容  
      if(eleType=='input' || eleType=='textarea' || eleType=='select' ){
        eles[i].value=propValue;
      }else{
        eles[i].innerHTML=propValue;
      }
    }
  }