Eu tenho uma configuração de exibição aninhada que pode se aprofundar um pouco no meu aplicativo. Há várias maneiras pelas quais eu poderia pensar em inicializar, renderizar e anexar as sub-visualizações, mas estou me perguntando o que é uma prática comum.
Aqui estão alguns que eu pensei:
initialize : function () {
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
},
render : function () {
this.$el.html(this.template());
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Prós: você não precisa se preocupar em manter a ordem DOM correta ao anexar. As visualizações são inicializadas desde o início, portanto, não há muito o que fazer de uma vez na função de renderização.
Contras: Você é forçado a delegar novamente novamenteEvents (), o que pode ser caro? A função de renderização da visualização pai está cheia de toda a renderização da subvisão que precisa acontecer? Você não tem a capacidade de definir os tagName
elementos, portanto, o modelo precisa manter os tagsNames corretos.
Outra maneira:
initialize : function () {
},
render : function () {
this.$el.empty();
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
this.$el.append(this.subView1.render().el, this.subView2.render().el);
}
Prós: você não precisa delegar novamente os eventos. Você não precisa de um modelo que contenha apenas espaços reservados vazios e os seus tagName voltem a ser definidos pela exibição.
Contras: agora você precisa anexar as coisas na ordem certa. A renderização da visualização pai ainda é confusa pela renderização da subvisão.
Com um onRender
evento:
initialize : function () {
this.on('render', this.onRender);
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
},
render : function () {
this.$el.html(this.template);
//other stuff
return this.trigger('render');
},
onRender : function () {
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Prós: a lógica da subvisão agora está separada do render()
método da visualização .
Com um onRender
evento:
initialize : function () {
this.on('render', this.onRender);
},
render : function () {
this.$el.html(this.template);
//other stuff
return this.trigger('render');
},
onRender : function () {
this.subView1 = new Subview();
this.subView2 = new Subview();
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Eu meio que misturei e combinei várias práticas diferentes em todos esses exemplos (desculpe por isso), mas quais são as que você gostaria de manter ou adicionar? e o que você não faria?
Resumo das práticas:
- Instanciar sub-visualizações dentro
initialize
ou dentrorender
? - Executar toda a lógica de renderização de sub-visualização em
render
ou dentroonRender
? - Use
setElement
ouappend/appendTo
?
fonte
close
método e umonClose
que limpa crianças, mas só estou curioso sobre como instanciar e renderizá-las em primeiro lugar.delete
em JS não é o mesmo quedelete
em C ++. É uma palavra-chave com um nome muito ruim, se você me perguntar.Respostas:
Eu geralmente vi / usei algumas soluções diferentes:
Solução 1
Isso é semelhante ao seu primeiro exemplo, com algumas alterações:
render()
é chamado APÓS o elemento da visualização interna ter sido colocado no DOM, o que é útil se orender()
método da visualização interna estiver se colocando / dimensionando-se na página com base na posição / tamanho de outros elementos (que é um caso de uso comum, na minha experiência)Solução 2
A solução 2 pode parecer mais limpa, mas causou algumas coisas estranhas na minha experiência e afetou negativamente o desempenho.
Geralmente uso a Solução 1, por alguns motivos:
render()
métodoLembre-se de que, se você estiver inicializando uma chamada
new View()
toda vezrender()
, ela será iniciadadelegateEvents()
assim mesmo. Portanto, isso não deve ser necessariamente um "golpe", como você já expressou.fonte
Este é um problema constante com o Backbone e, na minha experiência, não há realmente uma resposta satisfatória para esta pergunta. Eu compartilho sua frustração, especialmente porque há tão pouca orientação, apesar do quão comum é esse caso de uso. Dito isto, costumo usar algo semelhante ao seu segundo exemplo.
Antes de tudo, eu descartaria de imediato tudo o que exigisse que você delegasse novamente os eventos. O modelo de visualização orientada a eventos do Backbone é um dos componentes mais cruciais e perder essa funcionalidade simplesmente porque seu aplicativo não é trivial deixaria um gosto ruim na boca de qualquer programador. Então, arranhe o número um.
Em relação ao seu terceiro exemplo, acho que é apenas uma conclusão final da prática de renderização convencional e não acrescenta muito significado. Talvez se você estiver ativando um evento real ("
onRender
" não é um evento artificial ), valeria a pena vincular esses eventos arender
si mesmo. Se vocêrender
se sentir pesado e complexo, terá poucas subvisões.Volte ao seu segundo exemplo, que provavelmente é o menor dos três males. Aqui está um exemplo de código retirado de Recipes With Backbone , encontrado na página 42 da minha edição em PDF:
Essa é apenas uma configuração um pouco mais sofisticada que o seu segundo exemplo: eles especificam um conjunto de funções
addAll
eaddOne
fazem o trabalho sujo. Eu acho que essa abordagem é viável (e certamente a uso); mas ainda deixa um sabor bizarro. (Perdoe todas essas metáforas da língua.)Ao seu ponto de anexar na ordem correta: se você estiver anexando estritamente, com certeza, isso é uma limitação. Mas certifique-se de considerar todos os esquemas de modelos possíveis. Talvez você realmente queira um elemento de espaço reservado (por exemplo, um vazio
div
ouul
) que possa serreplaceWith
um novo elemento (DOM) que contém as subvisões apropriadas. Anexar não é a única solução, e você certamente pode contornar o problema de pedidos se você se importa muito com isso, mas eu imagino que você tenha um problema de design, se estiver enganando você. Lembre-se de que as subviews podem ter subviews, e deveriam, se for apropriado. Dessa forma, você tem uma estrutura semelhante a uma árvore, o que é bastante agradável: cada subvisão adiciona todas as suas subvisões, em ordem, antes que a visualização pai adicione outra, e assim por diante.Infelizmente, a solução 2 é provavelmente a melhor que você pode esperar para usar o Backbone pronto para uso. Se você estiver interessado em verificar bibliotecas de terceiros, uma que eu procurei (mas ainda não tive tempo para brincar) é o Backbone.LayoutManager , que parece ter um método mais saudável de adicionar sub-visualizações. No entanto, mesmo eles tiveram debates recentes sobre questões semelhantes a essas.
fonte
model.bind('remove', view.remove);
- você não deveria simplesmente fazer isso na função de inicialização do Compromisso para mantê-los separados?Surpreendeu que isso ainda não tenha sido mencionado, mas eu consideraria seriamente usar Marionette .
Ele aplica um pouco mais estrutura para aplicações de backbone, incluindo visão específica tipos (
ListView
,ItemView
,Region
eLayout
), adicionando adequadosController
s e muito mais.Aqui está o projeto no Github e um ótimo guia de Addy Osmani no livro Backbone Fundamentals para você começar.
fonte
Eu tenho, o que acredito ser, uma solução bastante abrangente para esse problema. Ele permite que um modelo dentro de uma coleção seja alterado e tenha apenas sua exibição renderizada novamente (em vez de toda a coleção). Ele também lida com a remoção de visualizações de zumbis através dos métodos close ().
Uso:
fonte
Confira este mixin para criar e renderizar subviews:
https://github.com/rotundasoftware/backbone.subviews
É uma solução minimalista que aborda muitos dos problemas discutidos neste encadeamento, incluindo ordem de renderização, não sendo necessário delegar novamente eventos etc. Observe que o caso de uma exibição de coleção (em que cada modelo da coleção é representado por um subview) é um tópico diferente. A melhor solução geral que conheço nesse caso é o CollectionView in Marionette .
fonte
Eu realmente não gosto de nenhuma das soluções acima. Eu prefiro para essa configuração que cada visualização precise trabalhar manualmente no método render.
views
pode ser uma função ou objeto retornando um objeto de definições de visualização.remove
são chamados, os.remove
filhos aninhados da ordem mais baixa para cima devem ser chamados (desde as visualizações sub-sub-sub)Aqui está um exemplo:
fonte
O backbone foi construído intencionalmente para que não houvesse prática "comum" em relação a esse e a muitos outros problemas. Ele deve ser o mais unopinionated possível. Teoricamente, você nem precisa usar modelos com o Backbone. Você pode usar javascript / jquery na
render
função de uma exibição para alterar manualmente todos os dados na exibição. Para torná-lo mais extremo, você nem precisa de umarender
função específica . Você poderia ter uma função chamadarenderFirstName
que atualiza o primeiro nome no dom erenderLastName
que atualiza o sobrenome no dom. Se você adotasse essa abordagem, seria muito melhor em termos de desempenho e nunca mais precisaria delegar eventos manualmente. O código também faria total sentido para alguém que o estivesse lendo (embora fosse um código mais longo / mais confuso).No entanto, geralmente não há desvantagem em usar modelos e simplesmente destruir e reconstruir a exibição inteira e suas subvisões em cada chamada de renderização, pois nem sequer ocorreu ao questionador fazer outra coisa. Então é isso que a maioria das pessoas faz em praticamente todas as situações em que se deparam. E é por isso que estruturas opinativas apenas tornam esse o comportamento padrão.
fonte
Você também pode injetar as subvisões renderizadas como variáveis no modelo principal como variáveis.
primeiro renderize as subvisões e converta-as em html assim:
var subview1 = $(subview1.render.el).html(); var subview2 = $(subview2.render.el).html();
(dessa forma, você também pode concatenar dinamicamente as visualizações como
subview1 + subview2
quando usadas em loops) e depois passá-las para o modelo principal que se parece com isso:... some header stuff ... <%= sub1 %> <%= sub2 %> ... some footer stuff ...
e injete-o finalmente assim:
this.$el.html(_.template(MasterTemplate, { sub1: subview1, sub2: subview2 } ));
Em relação aos Eventos nas subvisões: É provável que eles tenham que estar conectados no pai (masterView) com essa abordagem, não nas subvisões.
fonte
Eu gosto de usar a abordagem a seguir, que também remove as visualizações filho corretamente. Aqui está um exemplo do livro de Addy Osmani.
fonte
Não há necessidade de delegar novamente os eventos, pois é caro. Ver abaixo:
fonte