Esta é uma grande pergunta. O backbone é ótimo por causa da falta de suposições, mas significa que você precisa (decidir como) implementar coisas como essa. Depois de analisar minhas próprias coisas, acho que (meio que) uso uma mistura dos cenários 1 e 2. Não acho que exista um quarto cenário mágico porque, simplesmente, tudo o que você faz nos cenários 1 e 2 deve ser feito.
Eu acho que seria mais fácil explicar como eu gosto de lidar com isso com um exemplo. Digamos que esta página simples seja dividida nas visualizações especificadas:
Digamos que o HTML seja, depois de renderizado, algo como isto:
<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>
Espero que seja bastante óbvio como o HTML corresponde ao diagrama.
Ele ParentView
possui 2 visualizações filho InfoView
e PhoneListView
algumas divs extras, uma das quais #name
precisa ser definida em algum momento. PhoneListView
possui visualizações filho próprias, uma matriz de PhoneView
entradas.
Então, vamos à sua pergunta real. Lido com a inicialização e a renderização de maneira diferente, com base no tipo de exibição. Eu divido minhas visões em dois tipos, Parent
visões e Child
visões.
A diferença entre eles é simples: as Parent
visualizações mantêm as visualizações filho, enquanto as Child
visualizações não. Então, no meu exemplo, ParentView
e PhoneListView
são Parent
visualizações, enquanto InfoView
e as PhoneView
entradas são Child
visualizações.
Como mencionei antes, a maior diferença entre essas duas categorias é quando elas podem ser renderizadas. Em um mundo perfeito, quero que as Parent
visualizações sejam renderizadas apenas uma vez. Cabe às exibições filhas deles lidar com qualquer nova renderização quando os modelos forem alterados. Child
visualizações, por outro lado, permito reproduzir novamente a qualquer momento, pois elas não têm outras visualizações.
Em um pouco mais detalhadamente, para Parent
visualizações, gosto de minhas initialize
funções para fazer algumas coisas:
- Inicializar minha própria visão
- Renderizar minha própria visão
- Crie e inicialize todas as visualizações filho.
- Atribua a cada filho filho um elemento da minha visão (por exemplo, o
InfoView
seria atribuído #info
).
O passo 1 é bastante auto-explicativo.
A etapa 2, a renderização, é feita para que todos os elementos que os filhos exibem já existam antes que eu tente atribuí-los. Ao fazer isso, eu conheço todas as criançasevents
serão definidas corretamente e posso renderizar novamente seus blocos quantas vezes quiser, sem me preocupar em ter que delegar novamente nada. Na verdade, não tenho render
nenhuma visão infantil aqui, deixo que eles façam isso sozinhos initialization
.
As etapas 3 e 4 são realmente tratadas ao mesmo tempo em que passo el
ao criar a exibição filho. Gosto de passar um elemento aqui, pois acho que o pai deve determinar onde, em sua própria visão, o filho pode colocar seu conteúdo.
Para renderização, tento mantê-lo bastante simples para Parent
visualizações. Quero que a render
função não faça nada além de renderizar a exibição pai. Nenhuma delegação de evento, nenhuma renderização de visualizações filho, nada. Apenas uma renderização simples.
Às vezes, isso nem sempre funciona. Por exemplo, no meu exemplo acima, o #name
elemento precisará ser atualizado sempre que o nome no modelo for alterado. No entanto, esse bloco faz parte do ParentView
modelo e não é tratado por uma Child
exibição dedicada , portanto, resolvo isso. Vou criar algum tipo de subRender
função que substitui apenas o conteúdo do #name
elemento e não precisa descartar o #parent
elemento inteiro . Isso pode parecer um hack, mas eu realmente achei que funciona melhor do que ter que me preocupar em renderizar novamente todo o DOM e reconectar elementos. Se eu realmente quisesse torná-lo limpo, criaria uma nova Child
exibição (semelhante à InfoView
) que lidaria com o #name
bloco.
Agora, para Child
visualizações, ela initialization
é bastante semelhante às Parent
visualizações, apenas sem a criação de outras Child
visualizações. Assim:
- Inicializar minha visão
- A instalação vincula a escuta de quaisquer alterações no modelo de que me importo
- Renderizar minha visão
Child
ver renderização também é muito simples, basta renderizar e definir o conteúdo do meu el
. Novamente, não mexa com delegação ou algo assim.
Aqui está um exemplo de código de como minha ParentView
aparência pode ser:
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);
}
});
Você pode ver minha implementação subRender
aqui. Por ter alterações vinculadas a, e subRender
não render
, não preciso me preocupar em explodir e reconstruir todo o bloco.
Aqui está um código de exemplo para o InfoView
bloco:
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());
}
});
As ligações são a parte importante aqui. Ao vincular meu modelo, nunca preciso me preocupar em chamar manualmenterender
me . Se o modelo for alterado, esse bloco será renderizado novamente sem afetar outras visualizações.
O PhoneListView
será semelhante ao ParentView
, você só precisa de um pouco mais lógica em ambos os seus initialization
e render
funções para coleções punho. A decisão de como você lida com a coleção é realmente sua, mas pelo menos você precisará ouvir os eventos da coleção e decidir como deseja renderizar (acrescentar / remover ou apenas renderizar novamente o bloco inteiro). Pessoalmente, gosto de acrescentar novas exibições e remover as antigas, e não renderizar novamente a exibição inteira.
O PhoneView
será quase idêntico ao InfoView
, apenas ouvindo as mudanças de modelo com as quais se preocupa.
Espero que isso tenha ajudado um pouco, por favor, deixe-me saber se algo é confuso ou não é detalhado o suficiente.