Maison  >  Article  >  interface Web  >  Implémentez facilement la liaison bidirectionnelle des compétences javascript data_javascript

Implémentez facilement la liaison bidirectionnelle des compétences javascript data_javascript

WBOY
WBOYoriginal
2016-05-16 15:32:411289parcourir

Liaison de données bidirectionnelle signifie que lorsque les propriétés d'un objet changent, l'interface utilisateur correspondante peut être modifiée en même temps, et vice versa. En d’autres termes, si nous avons un objet utilisateur doté d’une propriété name, chaque fois que vous définissez une nouvelle valeur sur user.name, l’interface utilisateur affichera la nouvelle valeur. De même, si l'interface utilisateur contient une zone de saisie pour le nom de l'utilisateur, la saisie d'une nouvelle valeur entraînera la modification en conséquence de la propriété de nom de l'objet utilisateur.

De nombreux frameworks javascript populaires, comme Ember.js, Angular.js ou KnockoutJS, font la promotion de la liaison de données bidirectionnelle comme l'une de leurs principales fonctionnalités. Cela ne signifie pas que l’implémenter à partir de zéro est difficile, ni que l’utilisation de ces frameworks est notre seule option lorsque nous avons besoin de cette fonctionnalité. L'idée sous-jacente à l'intérieur est en fait assez basique, et sa mise en œuvre peut être résumée dans les trois points suivants :

  • Nous avons besoin d'un moyen de déterminer quel élément de l'interface utilisateur est lié à quelle propriété.
  • Nous devons surveiller les changements dans les propriétés et l'interface utilisateur
  • Nous devons propager les modifications à tous les objets liés et éléments de l'interface utilisateur.

Bien qu'il existe de nombreuses façons d'atteindre ces objectifs, un moyen simple et efficace consiste à l'implémenter via le modèle de publication-abonnement. La méthode est simple : nous pouvons utiliser l'attribut de données personnalisé comme attribut à lier dans le code HTML. Tous les objets JavaScript et éléments DOM liés ensemble s'abonneront à cet objet de publication-abonnement. Chaque fois que nous détectons un changement dans un objet Javascript ou un élément d'entrée HTML, nous transmettons le proxy d'événement à l'objet de publication-abonnement, puis transmettons et diffusons toutes les modifications qui se produisent dans les objets et éléments liés via celui-ci.

Un exemple simple implémenté avec jQuery

Il est assez simple et direct d'implémenter ce dont nous avons discuté ci-dessus via jQuery, car en tant que bibliothèque populaire, elle nous permet de nous abonner et de publier facilement des événements DOM, et nous pouvons également en personnaliser un :

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;
}

En ce qui concerne les objets JavaScript, voici un exemple d'implémentation minimale d'un modèle de données utilisateur :

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;
}

Maintenant, chaque fois que nous voulons lier les propriétés d'un objet à l'interface utilisateur, nous définissons simplement l'attribut de données approprié sur l'élément HTML correspondant.

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

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

Les modifications de valeur dans la zone de saisie seront automatiquement mappées à l'attribut de nom de l'utilisateur, et vice versa. Vous avez terminé !

Une implémentation qui ne nécessite pas jQuery

De nos jours, la plupart des projets utilisent généralement jQuery, donc l'exemple ci-dessus est tout à fait acceptable. Mais que se passe-t-il si nous devons être complètement indépendants de jQuery ? Eh bien, en fait, ce n'est pas difficile à faire (surtout lorsque nous ne prenons en charge que IE8 et supérieur). Enfin, il suffit d'observer les événements DOM à travers le modèle publication-abonnement.

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;
}

Le modèle de données peut rester inchangé, à l'exception de l'appel à la méthode trigger dans jQuery dans le setter, qui peut être remplacé par notre méthode de publication personnalisée dans PubSub.

// 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 );
  }
 }

 // ...
}

Nous l'avons expliqué à travers des exemples et avons une fois de plus obtenu les résultats souhaités avec moins d'une centaine de lignes de JavaScript pur maintenable. Nous espérons que cela sera utile à tout le monde pour réaliser une liaison bidirectionnelle de données JavaScript.

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn