Tengo tres formas diferentes de inicializar y representar una vista y sus subvistas, y cada una de ellas tiene diferentes problemas. Tengo curiosidad por saber si hay una mejor manera de resolver todos los problemas:
Escenario uno:
Inicialice los hijos en la función de inicialización de los padres. De esta manera, no todo se atasca en el renderizado, por lo que hay menos bloqueo en el renderizado.
initialize : function () {
//parent init stuff
this.child = new Child();
},
render : function () {
this.$el.html(this.template());
this.child.render().appendTo(this.$('.container-placeholder');
}
Los problemas:
El mayor problema es que llamar al renderizado en el padre por segunda vez eliminará todos los enlaces de eventos del niño. (Esto se debe a cómo funciona jQuery
$.html()
). Esto podría mitigarse llamando en suthis.child.delegateEvents().render().appendTo(this.$el);
lugar, pero luego, en el primer caso, y el más frecuente, estás haciendo más trabajo innecesariamente.Al agregar los elementos secundarios, obliga a la función de representación a conocer la estructura DOM de los padres para obtener el orden que desea. Lo que significa que cambiar una plantilla puede requerir actualizar la función de representación de una vista.
Escenario dos:
Inicialice los elementos secundarios en la imagen fija de los padres initialize()
, pero en lugar de agregarlos, use setElement().delegateEvents()
para establecer el elemento secundario en un elemento en la plantilla de los padres.
initialize : function () {
//parent init stuff
this.child = new Child();
},
render : function () {
this.$el.html(this.template());
this.child.setElement(this.$('.placeholder-element')).delegateEvents().render();
}
Problemas:
- Esto hace lo
delegateEvents()
necesario ahora, lo cual es un poco negativo, ya que solo es necesario en llamadas posteriores en el primer escenario.
Escenario tres:
Inicialice los hijos en el render()
método de los padres en su lugar.
initialize : function () {
//parent init stuff
},
render : function () {
this.$el.html(this.template());
this.child = new Child();
this.child.appendTo($.('.container-placeholder').render();
}
Problemas:
Esto significa que la función de renderizado ahora también debe estar vinculada con toda la lógica de inicialización.
Si edito el estado de una de las vistas secundarias, y luego llamo render en el padre, se creará un hijo completamente nuevo y se perderá todo su estado actual. Lo que también parece que podría ser peligroso para las pérdidas de memoria.
Realmente curioso por ver a tus muchachos en esto. ¿Qué escenario usarías? ¿O hay un cuarto mágico que resuelve todos estos problemas?
¿Alguna vez ha realizado un seguimiento de un estado representado para una Vista? ¿Decir una renderedBefore
bandera? Parece realmente extraño.
fuente
delegateEvents()
después delsetElement()
? Según los documentos: "... y mover los eventos delegados de la vista del elemento antiguo al nuevo", elsetElement
método en sí mismo debe manejar la nueva delegación de eventos.Respuestas:
Esta es una gran pregunta. La columna vertebral es excelente debido a la falta de suposiciones que hace, pero significa que debe (decidir cómo) implementar cosas como esta usted mismo. Después de revisar mis propias cosas, descubro que (más o menos) uso una combinación de escenario 1 y escenario 2. No creo que exista un cuarto escenario mágico porque, simplemente, todo lo que haces en los escenarios 1 y 2 debe ser hecho.
Creo que sería más fácil explicar cómo me gusta manejarlo con un ejemplo. Digamos que tengo esta página simple dividida en las vistas especificadas:
Digamos que el HTML es, después de ser renderizado, algo como esto:
Esperemos que sea bastante obvio cómo el HTML coincide con el diagrama.
El
ParentView
sostiene 2 vistas secundarias,InfoView
yPhoneListView
así como algunos divs adicionales, uno de los cuales,#name
, se debe establecer en algún momento.PhoneListView
contiene vistas secundarias propias, una serie dePhoneView
entradas.Entonces a su pregunta real. Manejo la inicialización y el renderizado de manera diferente según el tipo de vista. Divido mis puntos de vista en dos tipos,
Parent
puntos de vista yChild
puntos de vista.La diferencia entre ellos es simple, las
Parent
vistas tienen vistas secundarias mientras que lasChild
vistas no. Entonces, en mi ejemplo,ParentView
yPhoneListView
sonParent
vistas, whileInfoView
y lasPhoneView
entradas sonChild
vistas.Como mencioné antes, la mayor diferencia entre estas dos categorías es cuando se les permite renderizar. En un mundo perfecto, quiero que las
Parent
vistas solo se muestren una vez. Depende de sus vistas secundarias manejar cualquier representación cuando los modelos cambien.Child
vistas, por otro lado, permito volver a renderizar en cualquier momento que lo necesiten, ya que no tienen ninguna otra vista que se base en ellas.En un poco más de detalle, para las
Parent
vistas me gusta que misinitialize
funciones hagan algunas cosas:InfoView
se le asignaría#info
).El paso 1 se explica por sí mismo.
El paso 2, la representación, se realiza para que los elementos en los que se basan las vistas secundarias ya existan antes de que intente asignarlos. Al hacer esto, sé que todos los niños
events
estarán configurados correctamente, y puedo volver a renderizar sus bloques tantas veces como quiera sin preocuparme de tener que volver a delegar nada. En realidad, no veorender
ningún punto de vista infantil aquí, les permito que lo hagan dentro de los suyosinitialization
.Los pasos 3 y 4 se manejan realmente al mismo tiempo que paso
el
al crear la vista secundaria. Me gusta pasar un elemento aquí, ya que siento que el padre debe determinar dónde, según su propia opinión, el niño puede poner su contenido.Para la representación, trato de mantenerlo bastante simple para las
Parent
vistas. Quiero que larender
función no haga nada más que representar la vista principal. Sin delegación de eventos, sin representación de vistas secundarias, nada. Solo un simple render.Sin embargo, a veces esto no siempre funciona. Por ejemplo, en mi ejemplo anterior, el
#name
elemento deberá actualizarse cada vez que cambie el nombre dentro del modelo. Sin embargo, este bloque es parte de laParentView
plantilla y no es manejado por unaChild
vista dedicada , así que evito eso. Crearé algún tipo desubRender
función que solo reemplace el contenido del#name
elemento, y no tenga que desechar todo el#parent
elemento. Esto puede parecer un truco, pero realmente he descubierto que funciona mejor que tener que preocuparme por volver a representar todo el DOM y volver a conectar elementos y demás. Si realmente quisiera hacerlo limpio, crearía una nuevaChild
vista (similar a laInfoView
) que manejaría el#name
bloque.Ahora, para las
Child
vistas,initialization
es bastante similar a lasParent
vistas, solo que sin la creación de másChild
vistas. Entonces:Child
La visualización de renderizado también es muy simple, solo renderiza y configura el contenido de miel
. Una vez más, no te metas con la delegación ni nada de eso.Aquí hay un código de ejemplo de cómo se
ParentView
puede ver mi :Puedes ver mi implementación de
subRender
aquí. Al tener cambios vinculados ensubRender
lugar derender
, no tengo que preocuparme por volar y reconstruir todo el bloque.Aquí hay un código de ejemplo para el
InfoView
bloque:Los enlaces son la parte importante aquí. Al vincularme a mi modelo, nunca tengo que preocuparme de llamarme manualmente
render
. Si el modelo cambia, este bloque se volverá a representar sin afectar ninguna otra vista.El
PhoneListView
será similar a laParentView
, usted sólo necesita un poco más de la lógica, tanto en susinitialization
yrender
funciones a las colecciones de la manija. La forma en que maneja la colección depende de usted, pero al menos deberá escuchar los eventos de la colección y decidir cómo desea renderizar (agregar / eliminar o simplemente volver a renderizar todo el bloque). Personalmente, me gusta agregar nuevas vistas y eliminar las viejas, no volver a renderizar toda la vista.El
PhoneView
será casi idéntico alInfoView
sólo escuchar a los cambios en el modelo que se preocupa.Espero que esto haya ayudado un poco, avíseme si algo es confuso o no está lo suficientemente detallado.
fuente
render
dentro delinitialize
método es una mala práctica, ya que evita que seas más eficiente en los casos en que no quieres renderizar de inmediato. ¿Qué piensas sobre esto?PhoneListView
?No estoy seguro de si esto responde directamente a su pregunta, pero creo que es relevante:
http://lostechies.com/derickbailey/2011/10/11/backbone-js-getting-the-model-for-a-clicked-element/
El contexto en el que configuré este artículo es diferente, por supuesto, pero creo que las dos soluciones que ofrezco, junto con los pros y los contras de cada uno, deberían ayudarlo a avanzar en la dirección correcta.
fuente
Para mí, no parece la peor idea del mundo para diferenciar entre la configuración inicial y las configuraciones posteriores de sus puntos de vista a través de algún tipo de bandera. Para hacer esto limpio y fácil, la bandera debe agregarse a su propia Vista, que debe extender la Vista Backbone (Base).
Al igual que Derick, no estoy completamente seguro de si esto responde directamente a su pregunta, pero creo que al menos vale la pena mencionarlo en este contexto.
fuente
Kevin Peel da una gran respuesta: aquí está mi versión tl; dr:
fuente
Estoy tratando de evitar el acoplamiento entre puntos de vista como estos. Hay dos formas en que suelo hacerlo:
Usa un enrutador
Básicamente, permite que la función del enrutador inicialice la vista principal y secundaria. Por lo tanto, la vista no se conoce entre sí, pero el enrutador lo maneja todo.
Pasando el mismo el a ambas vistas
Ambos tienen conocimiento del mismo DOM, y puede ordenarlos de la forma que desee.
fuente
Lo que hago es dar a cada niño una identidad (que Backbone ya lo ha hecho por usted: cid)
Cuando Container realiza el renderizado, el uso de 'cid' y 'tagName' genera un marcador de posición para cada elemento secundario, por lo que en la plantilla, los elementos secundarios no tienen idea de dónde lo colocará el contenedor.
de lo que puedes usar
no se necesita un marcador de posición específico, y Contenedor solo genera el marcador de posición en lugar de la estructura DOM del niño. Cotainer y Children siguen generando elementos DOM propios y solo una vez.
fuente
Aquí hay una combinación ligera para crear y renderizar subvistas, que creo que aborda todos los problemas en este hilo:
https://github.com/rotundasoftware/backbone.subviews
El enfoque adoptado por este complemento es crear y representar subvistas después de la primera vez que se representa la vista principal. Luego, en representaciones posteriores de la vista principal, $ .detach los elementos de la subvista, vuelva a representar la matriz, luego inserte los elementos de la subvista en los lugares apropiados y vuelva a representarlos. De esta manera, los objetos de subvistas se reutilizan en representaciones posteriores y no es necesario volver a delegar eventos.
Tenga en cuenta que el caso de una vista de colección (donde cada modelo de la colección se representa con una subvista) es bastante diferente y creo que merece su propia discusión / solución. La mejor solución general que conozco para ese caso es el CollectionView en Marionette .
EDITAR: para el caso de la vista de colección, también puede consultar esta implementación más centrada en la interfaz de usuario , si necesita seleccionar modelos basados en clics y / o arrastrar y soltar para reordenar.
fuente