J'ai une configuration de vue imbriquée qui peut être un peu plus profonde dans mon application. Il y a un tas de façons dont je pourrais penser à l'initialisation, au rendu et à l'ajout des sous-vues, mais je me demande quelle est la pratique courante.
En voici quelques-uns auxquels j'ai pensé:
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();
}
Avantages: Vous n'avez pas à vous soucier de maintenir le bon ordre DOM avec l'ajout. Les vues sont initialisées très tôt, il n'y a donc pas grand chose à faire en même temps dans la fonction de rendu.
Inconvénients: Vous êtes obligé de re-déléguer les événements (), ce qui peut être coûteux? La fonction de rendu de la vue parente est encombrée de tout le rendu de sous-vue qui doit se produire? Vous n'avez pas la possibilité de définir les tagName
éléments, le modèle doit donc conserver les bons tagNames.
Autrement:
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);
}
Pour: Vous n'avez pas à déléguer à nouveau des événements. Vous n'avez pas besoin d'un modèle contenant uniquement des espaces réservés vides et votre tagName est de nouveau défini par la vue.
Inconvénients: vous devez maintenant vous assurer d'ajouter les éléments dans le bon ordre. Le rendu de la vue parente est toujours encombré par le rendu de la sous-vue.
Avec un onRender
événement:
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();
}
Avantages: La logique de sous-vue est désormais séparée de la render()
méthode de la vue .
Avec un onRender
événement:
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();
}
J'ai en quelque sorte mélangé et mis en correspondance un tas de pratiques différentes dans tous ces exemples (désolé à ce sujet) mais quelles sont celles que vous conserveriez ou ajouteriez? et que ne feriez-vous pas?
Résumé des pratiques:
- Instancier des sous-vues dans
initialize
ou dansrender
? - Exécuter toute la logique de rendu de sous-vue dans
render
ou dansonRender
? - Utilisez
setElement
ouappend/appendTo
?
la source
close
méthode et uneonClose
qui nettoie les enfants, mais je suis juste curieux de savoir comment les instancier et les rendre en premier lieu.delete
dans JS n'est pas le même que celuidelete
de C ++. C'est un mot-clé très mal nommé si vous me demandez.Réponses:
J'ai généralement vu / utilisé quelques solutions différentes:
Solution 1
Ceci est similaire à votre premier exemple, avec quelques modifications:
render()
est appelé APRÈS que l'élément de la vue intérieure a été placé dans le DOM, ce qui est utile si larender()
méthode de votre vue intérieure se place / se redimensionne sur la page en fonction de la position / taille des autres éléments (ce qui est un cas d'utilisation courant, d'après mon expérience)Solution 2
La solution 2 peut paraître plus propre, mais elle a causé des choses étranges dans mon expérience et a affecté négativement les performances.
J'utilise généralement la solution 1, pour plusieurs raisons:
render()
méthodeGardez à l'esprit que si vous initialisez un appel à
new View()
chaque foisrender()
, cette initialisation sera dedelegateEvents()
toute façon appelée . Cela ne devrait donc pas nécessairement être un "con", comme vous l'avez dit.la source
C'est un problème éternel avec Backbone et, d'après mon expérience, il n'y a pas vraiment de réponse satisfaisante à cette question. Je partage votre frustration, d'autant plus qu'il y a si peu d'indications malgré la fréquence de ce cas d'utilisation. Cela dit, je vais généralement avec quelque chose qui ressemble à votre deuxième exemple.
Tout d'abord, je rejetterais d'emblée tout ce qui vous oblige à re-déléguer des événements. Le modèle de vue événementielle de Backbone est l'un de ses composants les plus cruciaux, et perdre cette fonctionnalité simplement parce que votre application n'est pas triviale laisserait un mauvais goût dans la bouche de tout programmeur. Donc zéro numéro un.
En ce qui concerne votre troisième exemple, je pense que c'est juste une fin autour de la pratique de rendu conventionnelle et n'ajoute pas beaucoup de sens. Peut-être que si vous déclenchez un événement réel (c'est-à-dire pas un
onRender
événement artificiel " "), il vaudrait la peine de simplement lier ces événements àrender
lui-même. Si vous trouvez que vousrender
devenez lourd et complexe, vous avez trop peu de sous-vues.Revenons à votre deuxième exemple, qui est probablement le moindre des trois maux. Voici un exemple de code extrait de Recipes With Backbone , trouvé à la page 42 de mon édition PDF:
Ce n'est qu'une configuration légèrement plus sophistiquée que votre deuxième exemple: elles spécifient un ensemble de fonctions,
addAll
etaddOne
, qui font le sale boulot. Je pense que cette approche est réalisable (et je l'utilise certainement); mais cela laisse toujours un arrière-goût bizarre. (Pardonnez toutes ces métaphores de la langue.)À votre point sur l'ajout dans le bon ordre: si vous ajoutez strictement, bien sûr, c'est une limitation. Mais assurez-vous de considérer tous les schémas de modèles possibles. Peut-être aimeriez-vous en fait un élément d'espace réservé (par exemple, un vide
div
ouul
) que vous pouvez ensuitereplaceWith
créer un nouvel élément (DOM) contenant les sous-vues appropriées. L'ajout n'est pas la seule solution, et vous pouvez certainement contourner le problème de commande si vous vous en souciez autant, mais j'imagine que vous avez un problème de conception si cela vous fait trébucher. N'oubliez pas que les sous-vues peuvent avoir des sous-vues, et elles le devraient si cela est approprié. De cette façon, vous avez une structure plutôt arborescente, ce qui est assez sympa: chaque sous-vue ajoute toutes ses sous-vues, dans l'ordre, avant que la vue parente n'en ajoute une autre, et ainsi de suite.Malheureusement, la solution n ° 2 est probablement la meilleure que vous puissiez espérer pour utiliser Backbone prêt à l'emploi. Si vous souhaitez consulter des bibliothèques tierces, celle que j'ai examinée (mais avec laquelle je n'ai pas encore eu le temps de jouer) est Backbone.LayoutManager , qui semble avoir une méthode plus saine pour ajouter des sous-vues. Cependant, même eux ont eu des débats récents sur des questions similaires à celles-ci.
la source
model.bind('remove', view.remove);
- ne devriez-vous pas simplement faire cela dans la fonction d'initialisation du rendez-vous pour les garder séparés?Surpris que cela n'ait pas encore été mentionné, mais j'envisagerais sérieusement d'utiliser Marionette .
Il applique un peu plus de structure pour des applications de Backbone, y compris les types de vue spécifique (
ListView
,ItemView
,Region
etLayout
), ajoutant appropriésController
s et beaucoup plus.Voici le projet sur Github et un excellent guide d'Addy Osmani dans le livre Backbone Fundamentals pour vous aider à démarrer.
la source
J'ai, ce que je crois être, une solution assez complète à ce problème. Il permet à un modèle au sein d'une collection de changer et d'avoir uniquement sa vue restituée (plutôt que la collection entière). Il gère également la suppression des vues zombies via les méthodes close ().
Usage:
la source
Découvrez ce mixin pour créer et rendre des sous-vues:
https://github.com/rotundasoftware/backbone.subviews
C'est une solution minimaliste qui résout un grand nombre des problèmes abordés dans ce fil, y compris l'ordre de rendu, ne pas avoir à re-déléguer des événements, etc. Notez que le cas d'une vue de collection (où chaque modèle de la collection est représenté avec un subview) est un sujet différent. La meilleure solution générale que je connaisse pour ce cas est la CollectionView dans Marionette .
la source
Je n'aime vraiment aucune des solutions ci-dessus. Je préfère pour cette configuration que chaque vue doit effectuer manuellement un travail dans la méthode de rendu.
views
peut être une fonction ou un objet renvoyant un objet de définitions de vue.remove
est appelé, les.remove
enfants imbriqués de l'ordre le plus bas doivent être appelés (depuis les sous-sous-sous-vues)Voici un exemple:
la source
Backbone a été construit intentionnellement pour qu'il n'y ait pas de pratique "commune" à ce sujet et à bien d'autres problèmes. Il est censé être aussi sans opinion que possible. Théoriquement, vous n'avez même pas besoin d'utiliser des modèles avec Backbone. Vous pouvez utiliser javascript / jquery dans la
render
fonction d'une vue pour modifier manuellement toutes les données de la vue. Pour le rendre plus extrême, vous n'avez même pas besoin d'unerender
fonction spécifique . Vous pourriez avoir une fonction appeléerenderFirstName
qui met à jour le prénom dans le dom etrenderLastName
qui met à jour le nom de famille dans le dom. Si vous adoptiez cette approche, ce serait bien meilleur en termes de performances et vous n'auriez plus jamais à déléguer manuellement des événements. Le code aurait également un sens total pour quelqu'un qui le lirait (bien que ce soit un code plus long / plus compliqué).Cependant, il n'y a généralement aucun inconvénient à utiliser des modèles et simplement à détruire et à reconstruire la vue entière et ses sous-vues à chaque appel de rendu, car il n'est même pas venu à l'esprit de l'interrogateur de faire autre chose. C'est donc ce que font la plupart des gens dans pratiquement toutes les situations qu'ils rencontrent. Et c'est pourquoi les cadres d'opinion en font simplement le comportement par défaut.
la source
Vous pouvez également injecter les sous-vues rendues en tant que variables dans le modèle principal en tant que variables.
rendre d'abord les sous-vues et les convertir en html comme ceci:
var subview1 = $(subview1.render.el).html(); var subview2 = $(subview2.render.el).html();
(de cette façon, vous pouvez également concaténer dynamiquement les vues comme
subview1 + subview2
lorsqu'elles sont utilisées dans des boucles), puis les transmettre au modèle principal qui ressemble à ceci:... some header stuff ... <%= sub1 %> <%= sub2 %> ... some footer stuff ...
et injectez-le enfin comme ceci:
this.$el.html(_.template(MasterTemplate, { sub1: subview1, sub2: subview2 } ));
Concernant les événements dans les sous-vues: Ils devront probablement être connectés dans le parent (masterView) avec cette approche et non dans les sous-vues.
la source
J'aime utiliser l'approche suivante qui m'assure également de supprimer correctement les vues enfants. Voici un exemple du livre d'Addy Osmani.
la source
Il n'est pas nécessaire de redéléguer les événements car cela coûte cher. Voir ci-dessous:
la source