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 renderedBeforebandera? 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", elsetElementmé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
ParentViewsostiene 2 vistas secundarias,InfoViewyPhoneListViewasí como algunos divs adicionales, uno de los cuales,#name, se debe establecer en algún momento.PhoneListViewcontiene vistas secundarias propias, una serie dePhoneViewentradas.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,
Parentpuntos de vista yChildpuntos de vista.La diferencia entre ellos es simple, las
Parentvistas tienen vistas secundarias mientras que lasChildvistas no. Entonces, en mi ejemplo,ParentViewyPhoneListViewsonParentvistas, whileInfoViewy lasPhoneViewentradas sonChildvistas.Como mencioné antes, la mayor diferencia entre estas dos categorías es cuando se les permite renderizar. En un mundo perfecto, quiero que las
Parentvistas solo se muestren una vez. Depende de sus vistas secundarias manejar cualquier representación cuando los modelos cambien.Childvistas, 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
Parentvistas me gusta que misinitializefunciones hagan algunas cosas:InfoViewse 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
eventsestará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 veorenderningú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
elal 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
Parentvistas. Quiero que larenderfunció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
#nameelemento deberá actualizarse cada vez que cambie el nombre dentro del modelo. Sin embargo, este bloque es parte de laParentViewplantilla y no es manejado por unaChildvista dedicada , así que evito eso. Crearé algún tipo desubRenderfunción que solo reemplace el contenido del#nameelemento, y no tenga que desechar todo el#parentelemento. 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 nuevaChildvista (similar a laInfoView) que manejaría el#namebloque.Ahora, para las
Childvistas,initializationes bastante similar a lasParentvistas, solo que sin la creación de másChildvistas. Entonces:ChildLa 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
ParentViewpuede ver mi :Puedes ver mi implementación de
subRenderaquí. Al tener cambios vinculados ensubRenderlugar derender, no tengo que preocuparme por volar y reconstruir todo el bloque.Aquí hay un código de ejemplo para el
InfoViewbloque: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
PhoneListViewserá similar a laParentView, usted sólo necesita un poco más de la lógica, tanto en susinitializationyrenderfunciones 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
PhoneViewserá casi idéntico alInfoViewsó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
renderdentro delinitializemé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