Heim  >  Artikel  >  Web-Frontend  >  Implementieren Sie ganz einfach die bidirektionale Bindung von Javascript-Daten_Javascript-Fähigkeiten

Implementieren Sie ganz einfach die bidirektionale Bindung von Javascript-Daten_Javascript-Fähigkeiten

WBOY
WBOYOriginal
2016-05-16 15:32:411287Durchsuche

Zwei-Wege-Datenbindung bedeutet, dass bei einer Änderung der Eigenschaften eines Objekts gleichzeitig die entsprechende Benutzeroberfläche geändert werden kann und umgekehrt. Mit anderen Worten: Wenn wir ein Benutzerobjekt haben, das über eine Namenseigenschaft verfügt, zeigt die Benutzeroberfläche immer dann den neuen Wert an, wenn Sie einen neuen Wert für user.name festlegen. Wenn die Benutzeroberfläche ebenfalls ein Eingabefeld für den Namen des Benutzers enthält, führt die Eingabe eines neuen Werts dazu, dass sich die Namenseigenschaft des Benutzerobjekts entsprechend ändert.

Viele beliebte Javascript-Frameworks wie Ember.js, Angular.js oder KnockoutJS fördern die bidirektionale Datenbindung als eine ihrer Hauptfunktionen. Dies bedeutet nicht, dass die Implementierung von Grund auf schwierig ist, und auch nicht, dass die Verwendung dieser Frameworks unsere einzige Option ist, wenn wir diese Funktionalität benötigen. Die zugrunde liegende Idee ist eigentlich recht einfach und ihre Umsetzung lässt sich in den folgenden drei Punkten zusammenfassen:

  • Wir brauchen eine Möglichkeit zu bestimmen, welches UI-Element an welche Eigenschaft gebunden ist.
  • Wir müssen Änderungen an Eigenschaften und Benutzeroberfläche überwachen
  • Wir müssen Änderungen an alle gebundenen Objekte und UI-Elemente weitergeben.

Obwohl es viele Möglichkeiten gibt, diese Punkte zu erreichen, besteht eine einfache und effiziente Möglichkeit darin, sie über das Publish-Subscriber-Muster zu implementieren. Die Methode ist einfach: Wir können das benutzerdefinierte Datenattribut als das Attribut verwenden, das im HTML-Code gebunden werden muss. Alle miteinander verbundenen JavaScript-Objekte und DOM-Elemente abonnieren dieses Publish-Subscribe-Objekt. Jedes Mal, wenn wir eine Änderung in einem Javascript-Objekt oder einem HTML-Eingabeelement erkennen, übergeben wir den Ereignis-Proxy an das Publish-Subscribe-Objekt und übertragen und senden dann alle Änderungen, die in den gebundenen Objekten und Elementen auftreten, über ihn.

Ein einfaches Beispiel implementiert mit jQuery

Es ist ganz einfach und unkompliziert, das, was wir oben besprochen haben, über jQuery zu implementieren, da es uns als beliebte Bibliothek ermöglicht, DOM-Ereignisse einfach zu abonnieren und zu veröffentlichen, und wir können auch eines anpassen:

function DataBinder(object_id){
  // Use a jQuery object as simple PubSub
  var pubSub=jQuery({});

  // We expect a `data` element specifying the binding
  // in the form:data-bind-<object_id>="<property_name>"
  var data_attr="bind-"+object_id,
    message=object_id+":change";

  // Listen to chagne events on elements with data-binding attribute and proxy
  // then to the PubSub, so that the change is "broadcasted" to all connected objects
  jQuery(document).on("change","[data-]"+data_attr+"]",function(eve){
    var $input=jQuery(this);

    pubSub.trigger(message,[$input.data(data_attr),$input.val()]);
  });

  // PubSub propagates chagnes to all bound elemetns,setting value of
  // input tags or HTML content of other tags
  pubSub.on(message,function(evt,prop_name,new_val){
    jQuery("[data-"+data_attr+"="+prop_name+"]").each(function(){
      var $bound=jQuery(this);

      if($bound.is("")){
        $bound.val(new_val);
      }else{
        $bound.html(new_val);
      }
    });
  });
  return pubSub;
}

Was JavaScript-Objekte betrifft, ist hier ein Beispiel für eine minimale Benutzerdatenmodellimplementierung:

function User(uid){
  var binder=new DataBinder(uid),
    
    user={
      attributes:{},
      // The attribute setter publish changes using the DataBinder PubSub
      set:function(attr_name,val){
        this.attributes[attr_name]=val;
        binder.trigger(uid+":change",[attr_name,val,this]);
      },

      get:function(attr_name){
        return this.attributes[attr_name];
      },
    
      _binder:binder
    };

  // Subscribe to PubSub
  binder.on(uid+":change",function(evt,attr_name,new_val,initiator){
    if(initiator!==user){
      user.set(attr_name,new_val);
    }
  });

  return user;
}

Wenn wir nun die Eigenschaften eines Objekts an die Benutzeroberfläche binden möchten, legen wir einfach das entsprechende Datenattribut für das entsprechende HTML-Element fest.

// javascript 
var user=new User(123);
user.set("name","Wolfgang");

// html
<input type="number" data-bind-123="name" />

Wertänderungen im Eingabefeld werden automatisch dem Namensattribut des Benutzers zugeordnet und umgekehrt. Du bist fertig!

Eine Implementierung, die kein jQuery erfordert

Die meisten Projekte verwenden heutzutage im Allgemeinen jQuery, daher ist das obige Beispiel völlig akzeptabel. Was aber, wenn wir völlig unabhängig von jQuery sein müssen? Tatsächlich ist dies nicht schwierig (vor allem, wenn wir nur IE8 und höher unterstützen). Schließlich müssen wir nur noch DOM-Ereignisse anhand des Publish-Subscriber-Musters beobachten.

function DataBinder( object_id ) {
 // Create a simple PubSub object
 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( evt ) {
  var target = evt.target || evt.srcElement, // IE8 compatibility
    prop_name = target.getAttribute( data_attr );

  if ( prop_name && prop_name !== "" ) {
   pubSub.publish( message, prop_name, target.value );
  }
 };

 // Listen to change events and proxy to PubSub
 if ( document.addEventListener ) {
  document.addEventListener( "change", changeHandler, false );
 } else {
  // IE8 uses attachEvent instead of addEventListener
  document.attachEvent( "onchange", changeHandler );
 }

 // PubSub propagates changes to all bound elements
 pubSub.on( message, function( evt, 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;
}

Das Datenmodell kann unverändert bleiben, mit Ausnahme des Aufrufs der Trigger-Methode in jQuery im Setter, der durch unsere angepasste Veröffentlichungsmethode in PubSub ersetzt werden kann.

// In the model's setter:
function User( uid ) {
 // ...

 user = {
  // ...
  set: function( attr_name, val ) {
     this.attributes[ attr_name ] = val;
     // Use the `publish` method
     binder.publish( uid + ":change", attr_name, val, this );
  }
 }

 // ...
}

Wir haben es anhand von Beispielen erklärt und erneut die gewünschten Ergebnisse mit weniger als hundert Zeilen wartbarem reinem JavaScript erzielt. Wir hoffen, dass es für alle bei der Realisierung der bidirektionalen Bindung von JavaScript-Daten hilfreich sein wird.

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn