Questa è un'ottima domanda La spina dorsale è eccezionale a causa della mancanza di ipotesi che fa, ma significa che devi (decidere come) implementare cose come questa da solo. Dopo aver esaminato le mie stesse cose, trovo che (tipo di) uso un mix di scenario 1 e scenario 2. Non penso che esista un quarto scenario magico perché, semplicemente, tutto ciò che fai negli scenari 1 e 2 deve essere fatto.
Penso che sarebbe più semplice spiegare come mi piace gestirlo con un esempio. Supponiamo che questa semplice pagina sia suddivisa nelle viste specificate:
Supponiamo che l'HTML sia, dopo essere stato reso, qualcosa del genere:
<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>
Spero che sia abbastanza ovvio come l'HTML corrisponda al diagramma.
Il ParentView
stive 2 Visto bambino, InfoView
e PhoneListView
così come un paio di div in più, uno dei quali, #name
, deve essere impostata a un certo punto. PhoneListView
contiene viste secondarie proprie, una matrice di PhoneView
voci.
Quindi passiamo alla tua vera domanda. Gestisco l'inizializzazione e il rendering in modo diverso in base al tipo di vista. Suddivido le viste in due tipi, Parent
viste e Child
viste.
La differenza tra loro è semplice, le Parent
viste mantengono le viste figlio mentre le Child
viste no. Quindi nel mio esempio, ParentView
e PhoneListView
sono Parent
viste, mentre InfoView
e le PhoneView
voci sono Child
viste.
Come ho detto prima, la differenza più grande tra queste due categorie è quando è consentito il rendering. In un mondo perfetto, voglio che le Parent
viste vengano visualizzate solo una volta. Spetta alle loro viste figlio gestire qualsiasi nuovo rendering quando i modelli cambiano. Child
le viste, d'altra parte, concedo di eseguire nuovamente il rendering in qualsiasi momento necessario poiché non hanno altre viste che fanno affidamento su di esse.
Più in dettaglio, per le Parent
viste mi piace che le mie initialize
funzioni facciano alcune cose:
- Inizializza il mio punto di vista
- Rendi il mio punto di vista
- Crea e inizializza le viste figlio.
- Assegna a ciascun bambino una vista a mio avviso (ad es.,
InfoView
Sarebbe assegnata #info
).
Il passaggio 1 è piuttosto autoesplicativo.
Il passaggio 2, il rendering, viene eseguito in modo tale che tutti gli elementi su cui si basano le viste figlio esistano già prima che provi ad assegnarli. In questo modo, so che tutti i bambini events
saranno impostati correttamente e posso ri-renderizzare i loro blocchi tutte le volte che voglio senza preoccuparmi di dover delegare nuovamente qualsiasi cosa. In realtà non ho render
alcuna visione di bambino qui, lascio che lo facciano da soli initialization
.
I passaggi 3 e 4 vengono effettivamente gestiti contemporaneamente al passaggio el
durante la creazione della vista figlio. Mi piace inserire un elemento qui perché sento che il genitore dovrebbe determinare dove a suo avviso il bambino può mettere il suo contenuto.
Per il rendering, provo a renderlo piuttosto semplice per le Parent
viste. Voglio che la render
funzione non faccia altro che rendere la vista padre. Nessuna delegazione di eventi, nessun rendering di viste figlio, niente. Solo un semplice rendering.
A volte questo non funziona sempre però. Ad esempio, nel mio esempio sopra, l' #name
elemento dovrà essere aggiornato ogni volta che cambia il nome all'interno del modello. Tuttavia, questo blocco fa parte del ParentView
modello e non è gestito da una Child
vista dedicata , quindi ci aggiro. Creerò una sorta di subRender
funzione che sostituisce solo il contenuto #name
dell'elemento e non è necessario eliminare l'intero #parent
elemento. Questo può sembrare un trucco, ma ho davvero trovato che funziona meglio che doverti preoccupare di ripetere il rendering dell'intero DOM e ricollegare elementi e così via. Se volessi davvero renderlo pulito, creerei una nuova Child
vista (simile alla InfoView
) che gestirà il #name
blocco.
Ora per le Child
viste, initialization
è abbastanza simile alle Parent
viste, solo senza la creazione di ulteriori Child
viste. Così:
- Inizializza la mia vista
- Il programma di installazione vincola l'ascolto di eventuali modifiche al modello a cui tengo
- Rendi il mio punto di vista
Child
visualizzare il rendering è anche molto semplice, basta renderizzare e impostare il contenuto di my el
. Ancora una volta, non si scherza con la delegazione o qualcosa del genere.
Ecco un esempio di codice di come ParentView
potrebbe apparire il mio :
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);
}
});
Puoi vedere la mia implementazione di subRender
qui. Avendo le modifiche vincolate subRender
invece di render
, non devo preoccuparmi di far saltare in aria e ricostruire l'intero blocco.
Ecco un esempio di codice per il InfoView
blocco:
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());
}
});
I vincoli sono la parte importante qui. Legando al mio modello, non devo mai preoccuparmi di chiamarmi manualmente render
. Se il modello cambia, questo blocco si riattiverà da solo senza influire su altre viste.
Il PhoneListView
sarà simile a quello ParentView
, avrete solo bisogno di un po 'più logica in entrambe le vostre initialization
e render
le funzioni alle collezioni manico. Il modo in cui gestisci la raccolta dipende davvero da te, ma dovrai almeno ascoltare gli eventi della raccolta e decidere come renderizzare (aggiungi / rimuovi, o semplicemente esegui nuovamente il rendering dell'intero blocco). Personalmente mi piace aggiungere nuove viste e rimuovere quelle vecchie, non ricalcolare l'intera vista.
Il PhoneView
sarà quasi identico al InfoView
solo ascoltando il modello cambia si preoccupa.
Spero che questo abbia aiutato un po ', per favore fatemi sapere se qualcosa è confuso o non abbastanza dettagliato.