Das ist eine gute Frage. Backbone ist großartig, weil es keine Annahmen macht, aber es bedeutet, dass Sie solche Dinge selbst implementieren müssen. Nachdem ich meine eigenen Sachen durchgesehen habe, stelle ich fest, dass ich (irgendwie) eine Mischung aus Szenario 1 und Szenario 2 verwende. Ich glaube nicht, dass ein viertes magisches Szenario existiert, weil einfach alles, was Sie in Szenario 1 und 2 tun, sein muss getan.
Ich denke, es wäre am einfachsten zu erklären, wie ich mit einem Beispiel umgehen möchte. Angenommen, ich habe diese einfache Seite in die angegebenen Ansichten unterteilt:

Angenommen, der HTML-Code ist nach dem Rendern ungefähr so:
<div id="parent">
<div id="name">Person: Kevin Peel</div>
<div id="info">
First name: <span class="first_name">Kevin</span><br />
Last name: <span class="last_name">Peel</span><br />
</div>
<div>Phone Numbers:</div>
<div id="phone_numbers">
<div>#1: 123-456-7890</div>
<div>#2: 456-789-0123</div>
</div>
</div>
Hoffentlich ist es ziemlich offensichtlich, wie der HTML-Code mit dem Diagramm übereinstimmt.
Das ParentViewhält 2 Kind Ansichten, InfoViewund PhoneListViewsowie ein paar zusätzliche divs, von denen eines , #namemuss an einem bestimmten Punkt eingestellt werden. PhoneListViewEnthält eigene untergeordnete Ansichten, eine Reihe von PhoneViewEinträgen.
Also weiter zu Ihrer eigentlichen Frage. Ich gehe mit der Initialisierung und dem Rendern je nach Ansichtstyp unterschiedlich um. Ich teile meine Ansichten in zwei Typen ein, ParentAnsichten und ChildAnsichten.
Der Unterschied zwischen ihnen ist einfach: ParentAnsichten enthalten untergeordnete Ansichten, ChildAnsichten jedoch nicht. Also in meinem Beispiel ParentViewund PhoneListViewsind ParentAnsichten, während InfoViewund die PhoneViewEinträge ChildAnsichten sind.
Wie ich bereits erwähnt habe, besteht der größte Unterschied zwischen diesen beiden Kategorien darin, wann sie rendern dürfen. In einer perfekten Welt möchte ich, dass ParentAnsichten immer nur einmal gerendert werden. Es liegt an ihren untergeordneten Ansichten, das erneute Rendern durchzuführen, wenn sich die Modelle ändern. ChildAnsichten hingegen erlaube ich, sie jederzeit neu zu rendern, da sie keine anderen Ansichten haben, die sich auf sie stützen.
Für ParentAnsichten möchte ich, dass meine initializeFunktionen einige Dinge tun:
- Initialisieren Sie meine eigene Ansicht
- Machen Sie meine eigene Ansicht
- Erstellen und initialisieren Sie untergeordnete Ansichten.
- Weisen Sie jeder untergeordneten Ansicht ein Element in meiner Ansicht zu (z. B. das
InfoViewwürde zugewiesen werden #info).
Schritt 1 ist ziemlich selbsterklärend.
Schritt 2, das Rendern, wird ausgeführt, sodass alle Elemente, auf die sich die untergeordneten Ansichten stützen, bereits vorhanden sind, bevor ich versuche, sie zuzuweisen. Auf diese Weise weiß ich, dass alle Kinder eventsrichtig eingestellt sind, und ich kann ihre Blöcke so oft neu rendern, wie ich möchte, ohne mir Sorgen machen zu müssen, dass etwas neu delegiert werden muss. Ich habe hier eigentlich renderkeine kindlichen Ansichten, ich erlaube ihnen, das in ihren eigenen zu tun initialization.
Die Schritte 3 und 4 werden tatsächlich zur gleichen Zeit ausgeführt, zu der ich elbeim Erstellen der untergeordneten Ansicht übergebe. Ich möchte hier ein Element übergeben, da ich der Meinung bin, dass die Eltern bestimmen sollten, wo das Kind nach seiner eigenen Ansicht seinen Inhalt ablegen darf.
Beim Rendern versuche ich, es für ParentAnsichten ziemlich einfach zu halten . Ich möchte, dass die renderFunktion nur die übergeordnete Ansicht rendert. Keine Ereignisdelegation, kein Rendern von untergeordneten Ansichten, nichts. Nur ein einfaches Rendern.
Manchmal funktioniert das aber nicht immer. In meinem obigen Beispiel muss das #nameElement beispielsweise jedes Mal aktualisiert werden, wenn sich der Name im Modell ändert. Dieser Block ist jedoch Teil der ParentViewVorlage und wird nicht von einer dedizierten ChildAnsicht verarbeitet. Deshalb arbeite ich daran. Ich werde eine Art subRenderFunktion erstellen , die nur den Inhalt des #nameElements ersetzt und nicht das gesamte #parentElement in den Papierkorb werfen muss. Dies mag wie ein Hack erscheinen, aber ich habe wirklich festgestellt, dass es besser funktioniert, als sich Gedanken über das erneute Rendern des gesamten DOM und das erneute Anbringen von Elementen und dergleichen machen zu müssen. Wenn ich es wirklich sauber machen wollte, würde ich eine neue ChildAnsicht (ähnlich der InfoView) erstellen , die den #nameBlock handhaben würde .
Bei ChildAnsichten ist die Ansicht initializationziemlich ähnlich Parent, nur ohne dass weitere ChildAnsichten erstellt werden müssen. So:
- Initialisieren Sie meine Ansicht
- Setup bindet das Abhören von Änderungen an dem Modell, das mir wichtig ist
- Machen Sie meine Ansicht
ChildDas Rendern von Ansichten ist ebenfalls sehr einfach. Rendern Sie einfach den Inhalt von my und legen Sie ihn fest el. Wieder kein Durcheinander mit der Delegation oder so etwas.
Hier ist ein Beispielcode, wie mein ParentViewaussehen könnte:
var ParentView = Backbone.View.extend({
el: "#parent",
initialize: function() {
// Step 1, (init) I want to know anytime the name changes
this.model.bind("change:first_name", this.subRender, this);
this.model.bind("change:last_name", this.subRender, this);
// Step 2, render my own view
this.render();
// Step 3/4, create the children and assign elements
this.infoView = new InfoView({el: "#info", model: this.model});
this.phoneListView = new PhoneListView({el: "#phone_numbers", model: this.model});
},
render: function() {
// Render my template
this.$el.html(this.template());
// Render the name
this.subRender();
},
subRender: function() {
// Set our name block and only our name block
$("#name").html("Person: " + this.model.first_name + " " + this.model.last_name);
}
});
Sie können meine Implementierung subRenderhier sehen. Dadurch , dass Änderungen gebunden subRenderstatt render, habe ich nicht zu befürchten Strahlen weg und den Wiederaufbau des gesamten Blocks.
Hier ist ein Beispielcode für den InfoViewBlock:
var InfoView = Backbone.View.extend({
initialize: function() {
// I want to re-render on changes
this.model.bind("change", this.render, this);
// Render
this.render();
},
render: function() {
// Just render my template
this.$el.html(this.template());
}
});
Die Bindungen sind hier der wichtige Teil. Durch die Bindung an mein Modell muss ich mich nie mehr darum kümmern, rendermich selbst manuell anzurufen. Wenn sich das Modell ändert, wird dieser Block selbst neu gerendert, ohne andere Ansichten zu beeinflussen.
Das PhoneListViewwird dem ähnlich sein ParentView, Sie benötigen nur ein wenig mehr Logik sowohl in Ihrer initializationals auch in Ihren renderFunktionen, um Sammlungen zu verwalten. Wie Sie mit der Sammlung umgehen, liegt ganz bei Ihnen, aber Sie müssen zumindest die Sammlungsereignisse abhören und entscheiden, wie Sie rendern möchten (Anhängen / Entfernen oder einfach das Rendern des gesamten Blocks). Ich persönlich möchte neue Ansichten anhängen und alte entfernen, nicht die gesamte Ansicht neu rendern.
Das PhoneViewwird fast identisch mit dem sein InfoView, nur das Hören der Modelländerungen, die es interessiert.
Hoffentlich hat dies ein wenig geholfen. Bitte lassen Sie mich wissen, wenn etwas verwirrend oder nicht detailliert genug ist.