To świetne pytanie. Szkielet jest świetny ze względu na brak założeń, które sprawia, ale oznacza to, że musisz (zdecydować, jak) wdrożyć takie rzeczy samodzielnie. Po przejrzeniu moich własnych rzeczy stwierdzam, że (w pewnym sensie) używam kombinacji scenariusza 1 i scenariusza 2. Nie sądzę, aby istniał czwarty magiczny scenariusz, ponieważ po prostu wszystko, co robisz w scenariuszu 1 i 2, musi być Gotowe.
Myślę, że najłatwiej byłoby wyjaśnić na przykład, jak lubię sobie z tym poradzić. Powiedzmy, że mam tę prostą stronę podzieloną na określone widoki:
Powiedzmy, że HTML po renderowaniu wygląda mniej więcej tak:
<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>
Mamy nadzieję, że to dość oczywiste, jak HTML pasuje do diagramu.
ParentView
Posiada 2 widoki dziecko, InfoView
i PhoneListView
jak również kilka dodatkowych div, z których jeden, #name
, musi być ustawiony w pewnym momencie. PhoneListView
posiada własne widoki potomne, tablicę PhoneView
wpisów.
Tak więc na twoje aktualne pytanie. Inicjowanie i renderowanie wykonuję inaczej w zależności od typu widoku. Podzielam swoje poglądy na dwa typy: Parent
widoki i Child
widoki.
Różnica między nimi jest prosta, Parent
widoki zawierają widoki potomne, a Child
widoki nie. Więc w moim przykładzie, ParentView
i PhoneListView
są Parent
widoki, podczas gdy InfoView
a PhoneView
wpisy są Child
widoki.
Jak wspomniałem wcześniej, największą różnicą między tymi dwiema kategoriami jest to, kiedy można je renderować. W idealnym świecie chcę, aby Parent
widoki były renderowane tylko raz. Od ich widoków podrzędnych zależy, czy każde renderowanie zostanie zmienione po zmianie modelu (ów).Child
Z drugiej strony, zezwalam na ponowne renderowanie w dowolnym momencie, ponieważ nie mają na nich żadnych innych widoków.
Bardziej szczegółowo, dla Parent
widoków lubię moje initialize
funkcje, aby zrobić kilka rzeczy:
- Zainicjuj mój własny widok
- Renderuj mój własny widok
- Utwórz i zainicjuj wszelkie widoki potomne.
- Przypisz każdemu widokowi podrzędnemu element w moim widoku (np.
InfoView
Zostanie przypisany #info
).
Krok 1 jest dość oczywisty.
Krok 2, renderowanie, jest wykonywany, aby wszystkie elementy, na których polegają widoki potomne, już istniały, zanim spróbuję je przypisać. W ten sposób wiem, że wszystkie dzieci events
zostaną poprawnie ustawione i mogę ponownie renderować ich bloki tyle razy, ile chcę, nie martwiąc się o konieczność ponownej delegacji. W rzeczywistości nie widzę render
tutaj żadnych poglądów dzieci, pozwalam im to robić we własnym zakresie initialization
.
Kroki 3 i 4 są w rzeczywistości obsługiwane w tym samym czasie, w którym przechodzę el
podczas tworzenia widoku potomnego. Lubię przekazywać tutaj element, ponieważ uważam, że rodzic powinien określić, gdzie jego zdaniem dziecko może umieścić swoją treść.
Do renderowania staram się, aby Parent
widoki były dość proste . Chcęrender
funkcja nic więcej nie renderowała, niż renderowanie widoku nadrzędnego. Bez delegowania zdarzeń, bez renderowania widoków dzieci, nic. Po prostu prosty render.
Czasami jednak nie zawsze to działa. Na przykład w moim przykładzie powyżej #name
element będzie wymagał aktualizacji za każdym razem, gdy zmieni się nazwa w modelu. Jednak ten blok jest częścią ParentView
szablonu i nie jest obsługiwany przez dedykowany Child
widok, więc omijam to. Stworzę coś w rodzaju subRender
funkcji, która zastępuje tylko zawartość #name
elementu i nie musi niszczyć całego #parent
elementu. To może wydawać się włamaniem, ale naprawdę przekonałem się, że działa lepiej niż martwić się o ponowne renderowanie całego DOM i ponowne podłączanie elementów i tym podobne. Gdybym naprawdę chciał to wyczyścić, stworzyłbym nowy Child
widok (podobny do InfoView
), który obsługiwałby #name
blok.
Teraz dla Child
widoków initialization
jest bardzo podobny do Parent
widoków, tylko bez tworzenia kolejnych Child
widoków. Więc:
- Zainicjuj mój widok
- Instalator wiąże nasłuchując wszelkich zmian w modelu, na którym mi zależy
- Renderuj mój widok
Child
renderowanie widoku jest również bardzo proste, wystarczy wyrenderować i ustawić zawartość mojego el
. Znowu, nie zadzieraj z delegacją ani nic podobnego.
Oto przykładowy kod tego, jak ParentView
może wyglądać mój :
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);
}
});
Tutaj możesz zobaczyć moją implementację subRender
. Mając do czynienia ze zmianami subRender
zamiast render
, nie muszę się martwić o odpalenie i odbudowanie całego bloku.
Oto przykładowy kod dla InfoView
bloku:
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());
}
});
Wiązania są tutaj ważną częścią. Wiążąc się z moim modelem, nigdy nie muszę się martwić o ręczne wywołanie render
siebie. Jeśli model się zmieni, ten blok zrenderuje się sam, bez wpływu na inne widoki.
PhoneListView
Będzie podobny do ParentView
, to po prostu trzeba trochę więcej logiki w obu swoich initialization
and render
funkcje kolekcji klamek. Sposób obsługi kolekcji zależy od Ciebie, ale musisz przynajmniej wysłuchać wydarzeń związanych z kolekcją i zdecydować, jak chcesz renderować (dołączyć / usunąć lub po prostu zrenderować cały blok). Osobiście lubię dodawać nowe widoki i usuwać stare, a nie renderować cały widok.
PhoneView
Będzie prawie identyczny jak InfoView
tylko słuchać modelowych zmian to obchodzi.
Mam nadzieję, że to trochę pomogło, daj mi znać, jeśli coś jest mylące lub niewystarczająco szczegółowe.