Lecture recommandée:
Implémenter la liaison des données bidirectionnelle JS très simple
MVVM est un modèle de développement très populaire pour le Front-end Web. L'utilisation de MVVM peut rendre notre code plus concentré sur le traitement de la logique commerciale plutôt que sur les opérations DOM. Actuellement, les célèbres cadres MVVM incluent Vue, Avalon, React, etc. Ces cadres ont leurs propres avantages, mais l'idée de mise en œuvre est à peu près la même: la liaison des données + le rafraîchissement de la vue. Par curiosité et une volonté de lutter, j'ai également écrit la bibliothèque MVVM la plus simple (MVVM.JS) dans cette direction, avec un total de plus de 2 000 lignes de code. La dénomination et l'utilisation des instructions sont similaires à Vue. Ici, je partagerai les principes de mise en œuvre et les idées de mon code d'organisation du code.
Tri d'idées
MVVM est conceptuellement un modèle qui sépare vraiment les vues de la logique des données, et ViewModel est au centre de l'ensemble du modèle. Pour implémenter ViewModel, vous devez associer le modèle de données (modèle) et la vue (vue). L'idée de mise en œuvre entière peut être simplement résumé en 5 points:
Implémentez un compilateur pour scanner et extraire les instructions pour chaque nœud d'un élément;
Implémentez un analyseur pour analyser les instructions de l'élément, qui peuvent mettre à jour l'intention de l'instruction vers le DOM via une fonction de rafraîchissement (un module qui peut être spécifiquement responsable de la vision rafraîchissante peut être nécessaire au milieu). Par exemple, lors de l'analyse du nœud <p v-show = "iSShow"> </p>, obtenez d'abord la valeur d'iSShow dans le modèle, puis modifiez Node.style.Display selon ISShow pour contrôler l'affichage et la cachette des éléments;
La mise en œuvre d'un observateur peut lier la fonction de rafraîchissement de chaque instruction dans l'analyseur avec les champs correspondant au modèle;
Implémentez un observateur pour surveiller le changement de valeur de tous les champs de l'objet, et une fois la modification se produit, la dernière valeur peut être obtenue et le rappel de notification peut être déclenché;
Utilisez l'observateur pour établir une surveillance du modèle dans l'observateur. Lorsqu'une valeur du modèle change, la surveillance est déclenchée. Une fois que l'observateur a obtenu la nouvelle valeur, il appelle la fonction de rafraîchissement associée à l'étape 2, qui peut atteindre le but de rafraîchir la vue pendant que les données changent.
Exemple d'effet
Tout d'abord, jetons un coup d'œil à l'exemple d'utilisation finale, qui est similaire à l'instanciation d'autres cadres MVVM:
<div id = "mobile-list"> <h1 v-text = "title"> </h1> <ul> <li v-for = "Item in Brands"> <b v-text = "item.name"> </b> <span v-show = "showrank"> rank: {{item.rank}} </span> </li> </ul> </v> var élément = var élément = document.QuerySelector ('# mobile-list'); var vm = new Mvvm (élément, {'title': 'mobile list', 'showRank': true, 'marques': [{'name': 'pomme', 'rank': 1}, {'name': 'Galaxy', 'Rank': 2}, {name ':' name ' 3}]}); vm.set ('title', 'Top 3 Mobile Rank List'); // => <h1> Liste des 3 meilleurs rangs mobiles </h1>Division des modules
J'ai divisé MVVM en cinq modules à implémenter: compilateur de module de compilation, analyseur, affichage du module de rafraîchissement, observateur du module d'abonnement de données et observateur du module d'écoute des données. Le processus peut être brièvement décrit comme: Une fois le compilateur compile la commande, les informations d'instruction sont remises à l'analyseur pour l'analyse. L'analyseur met à jour la valeur initiale et souscrit à l'observateur pour les modifications des données. L'observateur surveille les données changent puis les renvoient à l'observateur. L'observateur informe le mise à jour du résultat du changement et trouve la fonction de rafraîchissement correspondante pour actualiser la vue.
Le processus ci-dessus est illustré sur la figure:
Ce qui suit est une description des principes de base de l'implémentation de ces cinq modules (le code n'est publié que sur les parties clés, veuillez aller sur mon github pour l'implémentation complète)
1. Compilateur de module de compilation
La responsabilité du compilateur est principalement de numériser et d'extraire les instructions pour chaque nœud de l'élément. Étant donné que le processus de compilation et d'analyse traversera la totalité de l'arbre de nœud plusieurs fois, afin d'améliorer l'efficacité de la compilation, dans le constructeur MVVM, convertissez d'abord l'élément en une copie des fragments de document. L'objet de compilation est ce fragment de document et ne doit pas être un élément cible. Une fois que tous les nœuds sont compilés, le fragment de document est ajouté au nœud réel d'origine.
VM.ComphieElement implémente la numérisation et l'extraction d'instructions de tous les nœuds de l'élément:
vm.compileelement = function (fragment, root) {var nœud, childnodes = fragment.childnodes; // scanne le nœud enfant pour (var i = 0; i <childnodes.length; i ++) {node = childnodes [i]; if (this.hasdirective (node)) {this. $ Uncompilen Scan le nœud enfant du nœud enfant if (node.childnodes.length) {this.compileelement (node, false);}} // scanne les nœuds enfants if (root) if (root) {this.compileallnodes ();}}La méthode VM ..........chancementnement des nodes compilera chaque nœud. Après avoir compilé un nœud, il sera supprimé de la file d'attente de cache. En même temps, vérifiez ceci. $ UncompileNodes.Length When Length === 0, cela signifie que toute compilation est terminée. Vous pouvez ajouter des fragments de document au nœud réel.
2. Analyser de module d'analyse d'instructions
Lorsque le compilateur de compilateur extrait les instructions de chaque nœud, il peut être envoyé à l'analyseur pour l'analyse. Chaque instruction a une méthode d'analyse différente. Toutes les instructions doivent seulement faire deux choses: l'une consiste à mettre à jour la valeur des données à la vue (état initial), et l'autre consiste à vous abonner à la fonction de rafraîchissement à la surveillance des modifications du modèle. Ici, nous utilisons l'analyse du texte en V comme exemple pour décrire la méthode d'analyse générale d'une directive:
parser.parsevText = function (node, modèle) {// Obtenez la valeur initiale définie dans le modèle var text = this. $ modèle [modèle]; // Mettez à jour le texte node.TextContent = text; // Node, Text); {node.textContent = dernier; // updater.upDaTenodeTextContent (node, texte);});}3. Watcher du module d'abonnement aux données
Dans l'exemple précédent, Watcher fournit une méthode de montre pour s'abonner aux modifications de données. Un paramètre est le modèle de champ de modèle et l'autre est la fonction de rappel. La fonction de rappel est déclenchée via l'observateur. La nouvelle valeur dernière et ancienne ancienne ancienne sont passées dans le paramètre. Une fois que l'observateur a obtenu la nouvelle valeur, il peut trouver le rappel (fonction de rafraîchissement) correspondant du modèle pour mettre à jour la vue. Les fonctions de modèle et de rafraîchissement sont une relation un-à-plusieurs, c'est-à-dire qu'un modèle peut avoir autant de fonctions de rappel (fonctions de rafraîchissement) qui le gèrent, par exemple: v-text = "title" et v-html = "title" Les instructions partagent un champ de modèle de données.
Ajouter un abonnement de données à la méthode d'implémentation Watcher.Watch est:
watcher.watch = fonction (champ, rappel, contexte) {var callbacks = this. $ watchcallbacks; if (! object.hasownproperty.call (this. $ modèle, champ)) {console.warn ('le champ:' + champ + 'n'existe pas dans le modèle! [];} // cache rappel [champ] .push ([rappel, contexte]);}Lorsque le champ de champ du modèle de données change, Watcher déclenche tous les rappels dans le tableau de cache qui se sont abonné au champ.
4. Observer du module de surveillance des données
L'observateur est la base fondamentale de toute la mise en œuvre MVVM. J'ai lu un article disant que OO (object.observe) enflammera la révolution de liaison des données et apportera une énorme influence sur le front-end. Malheureusement, le projet ES7 a abandonné OO! Il n'y a pas de support de navigateur actuellement! Heureusement, il existe également objet.DefineProperty qui peut simuler un observateur simple en interceptant les descripteurs d'accès (get and set) des propriétés d'objet:
// Intercepter les méthodes GET et SET de la propriété Prop de l'objet objet.defineProperty (objet, prop, {get: function () {return this.getValue (objet, prop);}, set: function (newValue) {var oldvalue = this.getValue (objet, prop); if (newValue! == Trigger Change Rappel This.triggerChange (Prop, newValue, OldValue);}}});Ensuite, il y a une autre question: comment surveiller les opérations du tableau (push, quart, etc.)? Tous les cadres MVVM sont implémentés en réécrivant le prototype du tableau:
Observer.RewRiteArrayMethods = fonction (array) {var self = this; var arrayproto = array.prototype; var arrayMethods = object.create (arrayproto); var méthodes = 'push | pop | shift | unshift | splice | tri | reverse'.split (' | '); Méthodes.ForEach (fonction (méthode) {object.defineproperty (arrayMethods, méthode, function () {var i = arguments.length; var original = arrayproto [méthode]; var args = nouveau tableau (i); while (i--) {args [i] = arguments [i];} var result = original.apply (this, args); // trugback callwe Méthode); Retour Result;});}); Array .__ Proto__ = ArrayMethods;}Cette méthode d'implémentation est référencée à partir de Vue. Je pense qu'il est très bien utilisé, mais l'attribut de longueur du tableau ne peut pas être écouté, donc dans MVVM, le tableau de la longueur doit être évité
5. Afficher le module de rafraîchissement Updater
Updater est le plus facile parmi les cinq modules, il vous suffit d'être responsable de la fonction de rafraîchissement correspondant à chaque instruction. Après une série de lancer et de laisser le résultat final à la mise à jour pour la vue ou les mises à jour d'événements, par exemple, la fonction de rafraîchissement du texte V est:
updater.updatenodeTextContent = fonction (node, texte) {node.textContent = text;}Fonction de rafraîchissement de la ligne V: style:
updater.upDatenodestyle = function (node, propriété, valeur) {node.style [propul] = valeur;}Implémentation de la liaison des données bidirectionnelle
La liaison bidirectionnelle des données des éléments de forme est l'une des plus grandes caractéristiques de MVVM:
En fait, le principe de mise en œuvre de cette fonction magique est également très simple. Il n'y a que deux choses à faire: l'une consiste à mettre à jour la valeur du formulaire lorsque les données changent, et l'autre consiste à mettre à jour les données lorsque la valeur du formulaire change, afin que la valeur des données soit liée à la valeur de formulaire.
Les modifications de données pour mettre à jour les valeurs de formulaire peuvent être facilement effectuées en utilisant le module Watcher mentionné ci-dessus:
watcher.watch (modèle, fonction (dernier, old) {input.value = dernier;}); 'Pour mettre à jour les données dans les modifications de formulaire, il vous suffit d'écouter les événements de changement de formulaire en temps réel et de mettre à jour les champs correspondants du modèle de données:
var modèle = this. $ modèle; input.addeventListEnr ('change', function () {modèle [champ] = this.value;}); 'Les autres formulaires Radio, Checkbox et Select sont le même principe.
Ce qui précède, l'ensemble du processus et les idées de mise en œuvre de base de chaque module ont été expliqués. La première fois que j'ai publié un article dans la communauté, mes compétences d'expression linguistique ne sont pas très bonnes. S'il y a de mauvais mots et de mauvaises choses écrites, j'espère que tout le monde pourra les critiquer et les corriger!
Conclusion
J'essaye ce simple MVVM.JS parce que j'ai utilisé Vue.js dans mon projet Framework, mais je viens d'utiliser son système d'instructions. De nombreuses fonctions n'ont été utilisées qu'environ un quart. J'ai pensé qu'il serait suffisant pour implémenter simplement la liaison aux données et la vue de vue. En conséquence, je n'ai pas trouvé une telle bibliothèque JavaScript, j'ai donc créé une telle roue moi-même.
Bien que les fonctions et la stabilité soient bien inférieures aux cadres MVVM populaires tels que Vue, et l'implémentation du code peut être relativement rude, beaucoup de connaissances ont été ajoutées en construisant cette roue ~ progrès réside dans le lancer!
À l'heure actuelle, mon MVVM.JS implémente uniquement la fonction la plus élémentaire. Je continuerai de l'améliorer et de le renforcer à l'avenir. Si vous êtes intéressé, veuillez en discuter et améliorer ensemble ~