Heim  >  Artikel  >  Web-Frontend  >  Nur 30 Codezeilen zur Implementierung von MVC_javascript-Techniken in Javascript

Nur 30 Codezeilen zur Implementierung von MVC_javascript-Techniken in Javascript

WBOY
WBOYOriginal
2016-05-16 15:15:271057Durchsuche

Seit etwa 2009 glänzt MVC nach und nach im Front-End-Bereich und löste schließlich mit der Einführung von React Native im Jahr 2015 eine große Explosion aus: AngularJS, EmberJS, Backbone, ReactJS, RiotJS, VueJS... .. Eine Reihe von Namen sind aufgetaucht und haben sich auf auffällige Weise verändert. Einige von ihnen sind nach und nach aus dem Blickfeld der Menschen verschwunden, andere wachsen immer noch schnell und einige haben bereits eine eigene Rolle in einem bestimmten ökologischen Umfeld übernommen. Aber egal was passiert, MVC hat und wird die Art und Weise, wie Front-End-Ingenieure denken und arbeiten, tiefgreifend beeinflussen.

Viele Beispiele zur Erklärung von MVC gehen von einem bestimmten Konzept eines bestimmten Frameworks aus, beispielsweise der Backbone-Sammlung oder dem Modell in AngularJS. Dies ist sicherlich ein guter Ansatz. Aber der Grund, warum ein Framework ein Framework und keine Klassenbibliothek (jQuery) oder ein Toolset (Underscore) ist, liegt darin, dass dahinter viele hervorragende Designkonzepte und Best Practices stehen. Diese Designessenzen ergänzen sich und sind miteinander verknüpft sind unverzichtbar, es ist nicht einfach, die Essenz eines bestimmten Entwurfsmusters in einem komplexen Rahmen in kurzer Zeit zu erkennen.

Das ist der Ursprung dieses Aufsatzes – der Prototypcode, der erstellt wurde, um jedem das Verständnis des Konzepts zu erleichtern, sollte so einfach wie möglich sein, gerade einfach genug, damit jeder das Konzept verstehen kann.

1. Die Grundlage von MVC ist das Beobachtermuster, das der Schlüssel zur Synchronisierung zwischen Modell und Ansicht ist
Der Einfachheit halber enthält jede Modellinstanz nur einen Grundwert.

function Model(value) {
  this._value = typeof value === 'undefined' ? '' : value;
  this._listeners = [];
}
Model.prototype.set = function (value) {
  var self = this;
  self._value = value;
  // model中的值改变时,应通知注册过的回调函数
  // 按照Javascript事件处理的一般机制,我们异步地调用回调函数
  // 如果觉得setTimeout影响性能,也可以采用requestAnimationFrame
  setTimeout(function () {
    self._listeners.forEach(function (listener) {
      listener.call(self, value);
    });
  });
};
Model.prototype.watch = function (listener) {
  // 注册监听的回调函数
  this._listeners.push(listener);
};
// html代码:
<div id="div1"></div>
// 逻辑代码:
(function () {
  var model = new Model();
  var div1 = document.getElementById('div1');
  model.watch(function (value) {
    div1.innerHTML = value;
  });
  model.set('hello, this is a div');
})();

Mit Hilfe des Beobachtermusters haben wir erkannt, dass beim Aufruf der Set-Methode des Modells zum Ändern seines Werts auch die Vorlage synchron aktualisiert wird. Diese Implementierung ist jedoch sehr umständlich, da wir die Änderung manuell überwachen müssen des Modellwerts (über die Watch-Methode) und die Übergabe einer Rückruffunktion. Gibt es eine Möglichkeit, die Bindung der Ansicht (eines oder mehrerer Dom-Knoten) an das Modell zu vereinfachen?

2. Implementieren Sie die Bindungsmethode und binden Sie das Modell und die Ansicht

Model.prototype.bind = function (node) {
  // 将watch的逻辑和通用的回调函数放到这里
  this.watch(function (value) {
    node.innerHTML = value;
  });
};
// html代码:
<div id="div1"></div>
<div id="div2"></div>
// 逻辑代码:
(function () {
  var model = new Model();
  model.bind(document.getElementById('div1'));
  model.bind(document.getElementById('div2'));
  model.set('this is a div');
})();

Durch eine einfache Kapselung hat die Bindung zwischen Ansicht und Modell Gestalt angenommen. Auch wenn mehrere Ansichten gebunden werden müssen, ist dies einfach zu implementieren. Beachten Sie, dass es sich bei bind um eine native Methode des Funktionsklassenprototyps handelt, die jedoch nicht eng mit MVC verwandt ist. Es ist prägnant und prägnant, daher kann ich die native Methode hier einfach vernachlässigen . Obwohl die Komplexität der Bindung verringert wurde, müssen wir diesen Schritt immer noch manuell durchführen. Ist es möglich, die Bindungslogik vollständig vom Geschäftscode zu entkoppeln?

3. Implementieren Sie den Controller, um die Bindung vom Logikcode zu entkoppeln

Aufmerksame Freunde haben vielleicht bemerkt, dass im obigen Artikel nur die Model-Klasse vorkommt. Es ist verständlich, dass HTML schließlich eine vorgefertigte Ansicht ist In diesem Artikel wird es auch von Anfang bis Ende erwähnt. Wenn Sie nur HTML als Ansicht verwenden, wird die View-Klasse nicht im Javascript-Code angezeigt. Warum ist die Controller-Klasse dann unsichtbar? Keine Sorge, der sogenannte „Logikcode“ ist tatsächlich ein Codesegment mit einem hohen Grad an Kopplung zwischen der Framework-Logik (nennen wir den Prototypen dieses Artikels ein Framework) und der Geschäftslogik.
Wenn Sie die Bindungslogik dem Framework überlassen möchten, müssen Sie dem Framework mitteilen, wie die Bindung abgeschlossen werden soll. Da es schwierig ist, Annotationen in JS abzuschließen, können wir diese Markup-Ebene in der Ansicht erstellen – die Verwendung des Tag-Attributs von HTML ist eine einfache und effektive Möglichkeit.

function Controller(callback) {
  var models = {};
  // 找到所有有bind属性的元素
  var views = document.querySelectorAll('[bind]');
  // 将views处理为普通数组
  views = Array.prototype.slice.call(views, 0);
  views.forEach(function (view) {
    var modelName = view.getAttribute('bind');
    // 取出或新建该元素所绑定的model
    models[modelName] = models[modelName] || new Model();
    // 完成该元素和指定model的绑定
    models[modelName].bind(view);
  });
  // 调用controller的具体逻辑,将models传入,方便业务处理
  callback.call(this, models);
}




// html:
<div id="div1" bind="model1"></div>
<div id="div2" bind="model1"></div>
// 逻辑代码:
new Controller(function (models) {
  var model1 = models.model1;
  model1.set('this is a div');
});


Ist das so einfach? So einfach ist das. Der Kern von MVC besteht darin, die Geschäftslogik im Controller zu vervollständigen und das Modell zu ändern. Gleichzeitig führen Änderungen im Modell zu automatischen Aktualisierungen der Ansicht. Diese Logik spiegelt sich im obigen Code wider und unterstützt mehrere Ansichten und Modelle. Obwohl es für Produktionsprojekte nicht ausreicht, hoffe ich, dass es für das MVC-Lernen aller einigermaßen hilfreich sein wird.

Der „Framework“-Code nach dem Sortieren und Entfernen von Kommentaren:

function Model(value) {
  this._value = typeof value === 'undefined' &#63; '' : value;
  this._listeners = [];
}
Model.prototype.set = function (value) {
  var self = this;
  self._value = value;
  setTimeout(function () {
    self._listeners.forEach(function (listener) {
      listener.call(self, value);
    });
  });
};
Model.prototype.watch = function (listener) {
  this._listeners.push(listener);
};
Model.prototype.bind = function (node) {
  this.watch(function (value) {
    node.innerHTML = value;
  });
};
function Controller(callback) {
  var models = {};
  var views = Array.prototype.slice.call(document.querySelectorAll('[bind]'), 0);
  views.forEach(function (view) {
    var modelName = view.getAttribute('bind');
    models[modelName] = models[modelName] || new Model();
    models[modelName].bind(view);
  });
  callback.call(this, models);
}

Nachtrag:

Obwohl der Autor beim Erlernen von Flux und Redux die Verwendung der Tools beherrscht, weiß ich es nur, weiß aber nicht, warum ich immer betont habe: „Flux meidet MVC zugunsten eines unidirektionalen Datenflusses.“ In der offiziellen ReactJS-Dokumentation verstehe ich nicht ganz, dass einseitiger Datenfluss und MVC nicht im Widerspruch stehen ist eins ohne ihn (vermeiden, meiden). Schließlich entschloss ich mich, zur Definition von MVC zurückzukehren und sie noch einmal zu studieren. Auch wenn ich bei meiner täglichen Arbeit nachlässig kopiere und einfüge, müssen wir immer noch eigensinnig sein und gelegentlich an den Wörtern kauen, oder? Diese Methode hat mir wirklich geholfen, diesen Satz zu verstehen. Hier kann ich meine Gedanken mit Ihnen teilen: Der Grund, warum ich das Gefühl habe, dass der einseitige Datenfluss in MVC und Flux ähnlich ist, könnte darin liegen, dass es keine klare Unterscheidung zwischen MVC und dem Beobachtermuster gibt Aufgrund der Beziehung basiert MVC auf dem Beobachtermuster, ebenso wie Flux. Die Quelle dieser Ähnlichkeit ist also das Beobachtermuster, nicht MVC und Flux selbst. Dieses Verständnis wird auch im ursprünglichen Design-Pattern-Buch der Vierer bestätigt: „Das erste und vielleicht bekannteste Beispiel des Observer-Patterns erscheint in Smalltalk Model/View/Controller (MVC), dem Benutzeroberflächen-Framework in der Smalltalk-Umgebung [KP88 ]. Die Model-Klasse von MVC spielt die Rolle des Subjekts, während View die Basisklasse für Beobachter ist.

Wenn Leser daran interessiert sind, einen solchen Spielzeugprototyp weiter auszubauen, können Sie sich auf die folgenden Anweisungen beziehen:

  • 1. Implementieren Sie die bidirektionale Bindung von Eingabeklassen-Tags
  • 2. Erzielen Sie eine präzise Steuerung des vom Controller gesteuerten Bereichs. Hier steuert ein Controller den gesamten DOM-Baum
  • 3. Implementieren Sie die Logik des Ausblendens/Anzeigens, Erstellens/Zerstörens von Dom-Knoten in der Ansichtsebene
  • 4. Integrieren Sie den virtuellen Dom, fügen Sie die Dom-Diff-Funktion hinzu und verbessern Sie die Rendering-Effizienz
  • 5. Stellen Sie eine Abhängigkeitsinjektionsfunktion bereit, um eine Umkehrung der Kontrolle zu erreichen
  • 6. Führen Sie Sicherheitsüberprüfungen für den Zuweisungsinhalt von innerHTML durch, um böswillige Einschleusung zu verhindern
  • 7. Implementieren Sie die Logik der Modellsammlung, bei der jedes Modell nur einen Wert hat
  • 8. Verwenden Sie den Setter in es5, um die Implementierung der Set-Methode zu ändern, wodurch es einfacher wird, das Modell zu ändern
  • 9. Fügen Sie die Kontrolle über Attribute und CSS in der Ansichtsebene hinzu
  • 10. Unterstützt eine Syntax ähnlich der doppelten Klammern in AngularJS und bindet nur einen Teil von HTML
  • ……

Ein komplettes Framework muss unzählige Verfeinerungen und Modifikationen durchlaufen. Der Weg ist noch lang.

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