Tengo una configuración de Vista anidada que puede ser algo profunda en mi aplicación. Hay muchas maneras en las que podría pensar en inicializar, renderizar y agregar las vistas secundarias, pero me pregunto qué es una práctica común.
Aquí hay una pareja en la que he pensado:
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();
}
Pros: no tiene que preocuparse por mantener el orden DOM correcto con los anexos. Las vistas se inicializan desde el principio, por lo que no hay tanto que hacer a la vez en la función de renderizado.
Contras: ¿ Estás obligado a volver a delegar eventos (), lo que puede ser costoso? ¿La función de representación de la vista principal está abarrotada con toda la representación de subvista que debe suceder? No tiene la capacidad de establecer los tagName
elementos, por lo que la plantilla debe mantener los nombres de etiqueta correctos.
De otra manera:
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);
}
Pros: no tiene que volver a delegar eventos. No necesita una plantilla que solo contenga marcadores de posición vacíos y la etiqueta vuelve a definir su nombre de etiqueta.
Contras: ahora debe asegurarse de agregar las cosas en el orden correcto. El renderizado de la vista principal todavía está abarrotado por el renderizado de la subvista.
Con un 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();
}
Pros: la lógica de la subvista ahora está separada del render()
método de la vista .
Con un 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();
}
He mezclado y comparado un montón de prácticas diferentes en todos estos ejemplos (lo siento mucho), pero ¿cuáles son las que mantendría o agregaría? y que no harias
Resumen de prácticas:
- ¿Instanciar subvistas en
initialize
o enrender
? - ¿Realiza toda la lógica de representación de subvista en
render
o enonRender
? - Usar
setElement
oappend/appendTo
?
fuente
close
método y un métodoonClose
que limpia a los niños, pero tengo curiosidad acerca de cómo crear instancias y renderizarlos en primer lugar.delete
en JS no es lo mismo quedelete
desde C ++. Es una palabra clave muy mal nombrada si me preguntas.Respuestas:
En general, he visto / usado un par de soluciones diferentes:
Solución 1
Esto es similar a su primer ejemplo, con algunos cambios:
render()
se llama DESPUÉS de que el elemento de la vista interna se haya colocado en el DOM, lo que es útil si su vista internarender()
método de está colocando / dimensionando en la página en función de la posición / tamaño de otros elementos (que es un caso de uso común, en mi experiencia)Solución 2
La solución 2 puede parecer más limpia, pero ha causado algunas cosas extrañas en mi experiencia y ha afectado negativamente el rendimiento.
Generalmente uso la Solución 1, por un par de razones:
render()
métodoTenga en cuenta que si está iniciando una llamada
new View()
cada vezrender()
, esa inicialización llamará dedelegateEvents()
todos modos. Así que eso no necesariamente debe ser una "estafa", como has expresado.fuente
Este es un problema permanente con Backbone y, en mi experiencia, no hay realmente una respuesta satisfactoria a esta pregunta. Comparto su frustración, especialmente porque hay muy poca orientación a pesar de lo común que es este caso de uso. Dicho esto, generalmente voy con algo similar a tu segundo ejemplo.
En primer lugar, descartaría de antemano cualquier cosa que requiera que vuelvas a delegar eventos. El modelo de vista basada en eventos de Backbone es uno de sus componentes más cruciales, y perder esa funcionalidad simplemente porque su aplicación no es trivial dejaría un mal sabor en la boca de cualquier programador. Así que rasca el número uno.
Con respecto a su tercer ejemplo, creo que es solo una ejecución final en torno a la práctica de renderizado convencional y no agrega mucho significado. Quizás si está activando un evento real (es decir, no un "
onRender
" evento artificial ), valdría la pena vincular esos eventos arender
sí mismo. Si tu encuentrasrender
difícil de manejar y complejo, tiene muy pocas subvistas.Volvamos a su segundo ejemplo, que probablemente sea el menor de los tres males. Aquí hay un código de ejemplo levantado de Recetas con Backbone , que se encuentra en la página 42 de mi edición PDF:
Esta es solo una configuración un poco más sofisticada que su segundo ejemplo: especifican un conjunto de funciones,
addAll
yaddOne
hacen el trabajo sucio. Creo que este enfoque es viable (y ciertamente lo uso); pero aún deja un sabor extraño. (Perdone todas estas metáforas de la lengua).A su punto de agregar en el orden correcto: si está agregando estrictamente, eso es una limitación. Pero asegúrese de considerar todos los posibles esquemas de plantillas. Quizás desee un elemento de marcador de posición (p. Ej., Un vacío
div
oul
) que luego puedareplaceWith
incluir un nuevo elemento (DOM) que contenga las subvistas apropiadas. Anexar no es la única solución, y ciertamente puede solucionar el problema de los pedidos si se preocupa tanto por eso, pero me imagino que tiene un problema de diseño si lo está tropezando. Recuerde, las subvistas pueden tener subvistas, y deberían tenerlas si es apropiado. De esa manera, tiene una estructura bastante similar a un árbol, lo cual es bastante agradable: cada subvista agrega todas sus subvistas, en orden, antes de que la vista principal agregue otra, y así sucesivamente.Desafortunadamente, la solución n. ° 2 es probablemente la mejor que puede esperar para usar Backbone listo para usar. Si está interesado en consultar bibliotecas de terceros, una que he examinado (pero que todavía no he tenido tiempo para jugar) es Backbone.LayoutManager , que parece tener un método más saludable para agregar subvistas. Sin embargo, incluso ellos han tenido debates recientes sobre temas similares a estos.
fuente
model.bind('remove', view.remove);
¿no deberías hacer eso en la función de inicialización de la cita para mantenerlos separados?Sorprendido, esto no se ha mencionado todavía, pero consideraría seriamente usar Marionette .
Se impone un poco más estructura para aplicaciones de red troncal, incluyendo tipos específicos de vista (
ListView
,ItemView
,Region
yLayout
), añadiendo adecuadosController
s y mucho más.Aquí está el proyecto en Github y una gran guía de Addy Osmani en el libro Backbone Fundamentals para comenzar.
fuente
Tengo, lo que creo que es, una solución bastante completa para este problema. Permite que un modelo dentro de una colección cambie, y solo se vuelve a representar su vista (en lugar de la colección completa). También maneja la eliminación de vistas de zombies a través de los métodos close ().
Uso:
fuente
Mira este mixin para crear y renderizar subvistas:
https://github.com/rotundasoftware/backbone.subviews
Es una solución minimalista que aborda muchos de los problemas discutidos en este hilo, incluido el orden de representación, no tener que volver a delegar eventos, etc. Tenga en cuenta que el caso de una vista de colección (donde cada modelo de la colección se representa con uno subvista) es un tema diferente. La mejor solución general que conozco para ese caso es la CollectionView en Marionette .
fuente
Realmente no me gusta ninguna de las soluciones anteriores. Prefiero esta configuración en lugar de que cada vista tenga que trabajar manualmente en el método de renderizado.
views
puede ser una función u objeto que devuelve definiciones de un objeto de vista.remove
se llama a un padre , el.remove
hijos anidados desde el orden más bajo (desde vistas sub-sub-sub)Aquí hay un ejemplo:
fuente
La columna vertebral fue construida intencionalmente para que no hubiera una práctica "común" con respecto a este y muchos otros temas. Está destinado a ser tan discreto como sea posible. Teóricamente, ni siquiera tiene que usar plantillas con Backbone. Puede usar javascript / jquery en la
render
función de una vista para cambiar manualmente todos los datos en la vista. Para hacerlo más extremo, ni siquiera necesita unarender
función específica . Podría tener una función llamadarenderFirstName
que actualiza el primer nombre en el dom yrenderLastName
que actualiza el apellido en el dom. Si adoptara este enfoque, sería mucho mejor en términos de rendimiento y nunca más tendría que delegar eventos manualmente. El código también tendría sentido para alguien que lo lea (aunque sería un código más largo / más desordenado).Sin embargo, generalmente no hay inconvenientes en usar plantillas y simplemente destruir y reconstruir toda la vista y sus subvistas en todas y cada una de las llamadas de renderizado, ya que ni siquiera se le ocurrió al interrogador hacer nada de otra manera. Así que eso es lo que la mayoría de la gente hace en casi todas las situaciones que encuentran. Y es por eso que los marcos obstinados simplemente hacen de este el comportamiento predeterminado.
fuente
También puede inyectar las subvistas renderizadas como variables en la plantilla principal como variables.
primero renderice las subvistas y conviértalas a html de esta manera:
var subview1 = $(subview1.render.el).html(); var subview2 = $(subview2.render.el).html();
(de esa manera, también podría concatenar dinámicamente las vistas como
subview1 + subview2
cuando se usa en bucles) y luego pasarlo a la plantilla maestra que se ve así:... some header stuff ... <%= sub1 %> <%= sub2 %> ... some footer stuff ...
e inyectarlo finalmente así:
this.$el.html(_.template(MasterTemplate, { sub1: subview1, sub2: subview2 } ));
Con respecto a los eventos dentro de las subvistas: lo más probable es que tengan que estar conectados en el padre (masterView) con este enfoque, no dentro de las subvistas.
fuente
Me gusta usar el siguiente enfoque que también se asegura de eliminar las vistas secundarias correctamente. Aquí hay un ejemplo del libro de Addy Osmani.
fuente
No es necesario volver a delegar eventos, ya que es costoso. Vea abajo:
fuente