Utilisation du prototype de JavaScript avec MVC

Dans cet article, nous passerons en revue le processus d'utilisation de JavaScript, du point de vue de MVC, pour manipuler le DOM. Plus spécifiquement, nous allons concevoir nos objets JavaScript, leurs propriétés et méthodes, et leurs instanciations parallèlement au comportement souhaité de nos vues (ce que l'utilisateur voit)..


Considérez vos vues comme des objets et non comme des pages

À tout moment du développement d'une page Web, nous utilisons un langage qui favorise naturellement le développement basé sur les classes ou le développement basé sur les objets. Dans les langages fortement typés tels que Java et C #, nous écrivons généralement nos vues dans des classes - en leur donnant l'état, la portée et le contexte. Lorsque nous travaillons avec des langages tels que PHP ou des moteurs de vue plus récents, tels que Razor pour ASP.NET, nos vues peuvent simplement être du balisage (HTML / CSS) mélangé à des modèles. Cependant, cela ne signifie pas que nous devons changer notre perception de la façon dont la vue se comporte comme sa propre entité avec état.

Dans Views, nous travaillons principalement avec HTML, composé d'éléments imbriqués. ces éléments ont des attributs qui décrivent quel est leur but sémantique ou comment ils apparaissent lors du rendu. Ces éléments ont ensuite des enfants ou des éléments parents qui héritent / fournissent des comportements en cascade (via CSS) et des comportements block / inline. Ces éléments peuvent naturellement être visualisés du point de vue de la programmation orientée objet (Object-Oriented Programming). Considérons, par exemple, le balisage suivant:

 div.container border: 1px solid # 333; rembourrage: 5px; La couleur rouge; 
 

Au sujet de notre compagnie

Résultat :

Comme vous pouvez le voir ci-dessus, l'en-tête a hérité de la propriété de couleur de police de son conteneur parent via le comportement CSS en cascade. Ce comportement est assez similaire au concept d'héritage en POO. Nous pouvons également voir que l'en-tête est un enfant du conteneur, héritant de certaines propriétés, en fonction du comportement de l'élément. Lorsque nous voyons nos éléments de ce point de vue, nous avons une meilleure définition de ce que nous entendons faire avec nos éléments de vue et nous pouvons mieux encapsuler les styles et les fonctionnalités..

Dans une vue, nous aurons un balisage. Toutefois, ce balisage peut comporter des vues partielles imbriquées telles que des barres latérales, un en-tête, un pied de page, un rail droit (ou gauche) et une ou plusieurs sections de contenu. Toutes ces vues partielles doivent être considérées comme leur propre entité, pouvant avoir leur propre état, contexte et portée..

"Lorsque vous concevez vos vues et des vues partielles en tant qu'objets, il est beaucoup plus facile d'écrire votre code côté client."


Traduire ce concept dans vos styles et scripts

De nombreux développeurs ont tendance à écrire du JavaScript d'un point de vue procédural ou fonctionnel, et négligent souvent de prendre en compte les tendances naturelles offertes par les approches de développement à base de vues et l'instanciation parallèle (création d'une nouvelle instance de la vue lors de la création d'une nouvelle instance de JavaScript objet correspondant à cette vue) lorsque vous travaillez dans des cadres MVC. Il arrive souvent que je rencontre des fichiers JavaScript qui ne sont qu'une méthode après l'autre. Bien que ce comportement fonctionne et soit courant, il n’est pas très efficace pour la maintenance du code, le débogage ou l’extension du code actuel ou futur lorsque vous travaillez beaucoup avec des vues..

Pour vous écarter de cette habitude et commencer à écrire un meilleur code de comportement, suivez les règles générales suivantes lorsque vous commencez à disposer les scripts et les styles de votre View, procédez comme suit:

Règles d'or du développement JavaScript basé sur View

  • Chaque vue rendue à partir d'une action sur un contrôleur doit avoir son propre objet JavaScript..
  • Chaque vue partielle chargée dans une vue doit avoir son propre objet JavaScript..
  • Nommez vos objets de la même manière que vos vues (ou vues partielles). Cela fera plus de sens pour vous et tous les autres qui touchent votre code.
  • Utilisez le cas Pascal pour tous les objets (c'est-à-dire À propos, Barre latérale, etc.). Vos vues devraient déjà, alors pourquoi ne pas faire la même chose pour vos objets JavaScript?
  • Toutes les constantes de ces objets doivent être stockées dans le constructeur. Cela signifie que si votre vue a des propriétés qui seront utilisées dans plusieurs méthodes, ces méthodes peuvent toutes accéder à ces propriétés..
  • Toutes les méthodes appelées dans une vue (ou une vue partielle) doivent être liées au prototype de l'objet qui correspond à cette vue..
  • Toutes les liaisons d'événement pour la vue (ou vue partielle) doivent être contenues dans la méthode de leur propre liaison d'événement, qui est placée sur le prototype..

Considérez le diagramme suivant:

Je crée généralement des scripts et des styles spécifiques à une vue, puis je récupère ce dont j'ai besoin dans les principales feuilles de style et bibliothèques de scripts que j'ai créées et qui seraient utilisées dans de nombreuses vues. Cela réduit également la quantité de code utilisée.


Création d'objets basés sur une vue

Dans cet article, nous allons présenter la structure de la page À propos de nous sur un site basé sur MVC. Pour commencer, nous allons créer la structure comme indiqué ci-dessus dans le diagramme précédent. À partir de là, nous allons créer un objet About et commencer à ajouter des méthodes au prototype. Tout d'abord, considérons la disposition visuelle suivante:

Ceci est une mise en page très logique et couramment utilisée pour une page Web. Nous pouvons segmenter notre page en objets visuels distincts. Pour chacune de ces vues, nous pouvons créer un objet logique qui lui correspondra. En règle générale, j'omets les informations répétitives du nom de fichier ou du nom de classe utilisé par MVC pour déterminer l'URI de la route. Au lieu de cela, je conserve un élément facile à maintenir cohérent..

Pour les pages vues, j'appelle généralement mes objets JavaScript par le nom de la vue. Voici un exemple de mon objet AboutView:

 // Voir le nom du fichier: AboutView.cs (.NET MVC 1.0), About.cshtml (.NET MVC 3.0) ou AboutView.php (PHP) var About = fonction (pageTitle) this.pageTitle = pageTitle; // événements de liaison dès que l'objet est instancié this.bindEvents (); ;

Dans l'exemple ci-dessus, nous avons créé un objet JavaScript au format de fonction, ce qui lui permet de servir de constructeur d'objet pour toutes les méthodes appelées pour la vue about. En choisissant ce format, nous pouvons instancier une nouvelle instance de ce, comme nous le faisons avec notre point de vue côté serveur (en disant nouveau AboutView ();). À partir de là, nous pouvons affecter des propriétés et des méthodes à cet objet. Pour assigner des méthodes à cet objet, nous aurons besoin d'accéder au prototype de l'objet..


Le prototype de JavaScript est votre ami

Les développeurs sont souvent contrariés par le caractère insaisissable (et l'ambiguïté) du prototype d'objet de JavaScript..

Les développeurs sont souvent contrariés par le caractère insaisissable (et l'ambiguïté) du prototype d'objet de JavaScript. Pour beaucoup, il peut être déroutant d’utiliser et de comprendre et ajoute une autre dimension au codage. À mesure que JavaScript devient davantage axé sur les événements avec les concepts HTML5, AJAX et Web 2.0, JavaScript tend naturellement à s’appuyer sur un développement procédural facile à développer mais difficile à maintenir, à adapter et à reproduire..

Pense au mot Prototype comme un abus de langage pour l'instant. Quand je pense Prototype, Je pense à un "brouillon" ou à une base pour l'héritage, mais ce n'est pas exactement le cas.

"En réalité, la meilleure perspective pour Prototype serait le pointeur de l'objet en mémoire."

Lorsque nous créons un objet, nous en instancions une nouvelle instance. Lorsque nous faisons cela, nous créons un emplacement dans la mémoire où l’objet peut être référencé (rappelez-vous, les objets en JavaScript sont types de référence, types non primitifs; créer une autre variable égale à cet objet puis modifier ses valeurs modifiera en réalité l'objet d'origine dans le pointeur). Lorsque nous créons un objet, instancions une nouvelle instance de celui-ci, puis modifions son "pointeur" ou Prototype, nous ajoutons directement des champs et des méthodes à cet objet en mémoire (nous souhaitons évidemment ajouter toutes ces choses avant l'instanciation).

Voici un exemple de création de méthodes sur le Sur prototype de l'objet:

 var About = function (pageTitle) this.pageTitle = pageTitle; // événements de liaison dès que l'objet est instancié this.bindEvents (); ; var About.prototype.bindEvents = function () // Contexte actuel: "ceci" est l'objet About // Placez toutes vos liaisons d'événements au même endroit et appelez-les // dans leurs propres méthodes, si nécessaire. $ ('ul.menu'). on ('cliquez sur', 'li.search', $ .proxy (this.toggleSearch, this)); ; var About.prototype.toggleSearch = function (e) // Basculer la fonction de recherche sur la page;

Comme vous pouvez le voir ci-dessus, nous avons contenu les propriétés de l’objet À propos dans le constructeur, créé un seul point de référence pour les événements de liaison (dans ce cas, nous utilisons jQuery pour créer les liaisons d’événements, mais vous pouvez utiliser n’importe quel framework. JavaScript lui-même) et ont placé la méthode toggleSearch sur le prototype de l’objet À propos de afin de contenir cette méthode dans cet objet. Nous avons aussi appelé le bindEvents () méthode dans l'objet pour qu'il soit appelé sur l'instanciation.

Considérons maintenant le code suivant pour la vue partielle de la barre latérale:

 var pSidebar = function (pageTitle) this.pageTitle = pageTitle; // appelle la méthode bindEvents lors de l'instanciation de l'objet pSidebar. // cela va lier les événements à l'objet this this.bindEvents (); ; var pSidebar.prototype.bindEvents = function () // contexte actuel: 'ceci' est l'objet de la barre latérale $ ('ul.menu'). on ('cliquez', 'li.has-sous-menu', $ .proxy ( this.toggleSubMenu, this)); $ ('input # search'). on ('click', $ .proxy (this.openSearch, this)); ; var pSidebar.prototype.toggleSubMenu = function (e) // bascule le sous-menu // contexte actuel: 'ceci' est le pSidebar obj;

REMARQUE: J'ai appelé l'objet pSidebar parce que c'est un vue partielle, pas une vue complète. C'est ma préférence pour faire la distinction entre les deux, mais rend les choses plus claires.

L'intérêt d'utiliser cette approche est que nous pouvons utiliser les mêmes noms de méthodes que ceux utilisés dans l'objet À propos et nous n'aurons aucun conflit. C’est parce que ces méthodes sont liées à l’objet prototype lui-même, pas l'espace de noms global. Cela simplifie notre code et permet une sorte de "modèle" pour les scripts futurs.


Instancier seulement au besoin

Une fois que vous avez créé vos objets, les appeler est simple. Vous n'avez plus besoin de dépendre de votre infrastructure pour déclencher des événements lorsque votre document est chargé ou prêt. Maintenant, vous pouvez simplement instancier votre objet et ses événements seront liés et exécutés selon les besoins. Alors, instancions notre Sur objet:

Dans votre vue où vous appelez des scripts spécifiques à cette vue (selon votre langage de modélisation), appelez simplement une nouvelle instance de votre objet et incluez le fichier comme suit:

  

Comme vous pouvez le constater, j’ai passé le titre de la page pour la vue (ce qui peut être n’importe quel argument pour n’importe quel besoin - même Données de modèle. Cela vous donne un excellent contexte sur les données de votre modèle et vous permet de manipuler ces données en JavaScript très facilement.

Juste comme votre Sur Objet, appeler vos vues partielles est tout aussi facile. Je vous recommande vivement d'appeler de nouvelles instances de vos objets JavaScript de vue partielle dans le constructeur de l'objet. Cela garantit que vous ne les appelez que si vous en avez besoin et qu'ils sont collectivement au même endroit..

 var About = function (pageTitle) this.pageTitle = pageTitle; // affectation d'une nouvelle instance de la vue partielle de la barre latérale à référencer ultérieurement this.sidebar = new pSidebar (pageTitle); // NOTE: Si vous n'avez pas besoin de référencer une vue partielle après le fait, // vous pouvez simplement en instancier une instance sans l'assigner dans le constructeur de l'objet, comme suit: new pSidebar (pageTitle); // faire de même pour le pied de page partiel Voir this.footer = new pFooter (); // événements de liaison dès que l'objet est instancié this.bindEvents (); ;

Comme vous pouvez le constater, en référençant l'objet Sidebar en tant que propriété locale de l'objet About, nous lions maintenant cette instance, ce qui est un comportement très naturel - cette instance est maintenant la barre latérale About Page..

Si vous n'avez pas besoin de référencer une vue partielle après le fait, vous pouvez simplement en instancier une instance sans l'affecter dans le constructeur de l'objet, comme suit:

 var About = function (pageTitle) this.pageTitle = pageTitle; nouvelle pSidebar (pageTitle); // événements de liaison dès que l'objet est instancié this.bindEvents (); ;

A partir de là, tout ce que nous avons à faire est d’ajouter un autre script à nos scripts appelé à notre avis:

   

Pourquoi cette technique est bénéfique

Une fois que cette structure est en place, nous pouvons ensuite adapter notre objet JavaScript à notre vue et appliquer les méthodes nécessaires à cet objet pour conserver la portée. En créant un objet parallèle à une vue et en travaillant à partir du prototype de cet objet, nous constatons les avantages suivants:

  1. La nomenclature facilite la navigation dans le code
  2. Nous avons naturellement un espace de noms pour nos objets, ce qui réduit le besoin de noms de méthode longs et l'utilisation excessive de la fermeture anonyme..
  3. Peu ou pas de conflit dans un autre code car nos méthodes sont basées sur le prototype de l'objet, pas au niveau global
  4. Lors de l'instanciation de nos vues partielles dans le constructeur d'objet de notre vue et de leur affectation à une référence de variable locale, nous créons effectivement une copie liée localement de l'objet de cette vue partielle..
  5. Nous avons une définition précise du contexte et sommes en mesure d'utiliser le mot clé 'this' sans souci.
  6. Le débogage devient clair car toutes les méthodes présentées dans la pile sont liées en un seul endroit.

Conclusion

Alors que le modèle de conception MVC continue de gagner en popularité dans le monde de la conception, le développement d'objets JavaScript pour accompagner la manipulation des éléments DOM changera pour devenir plus adapté à la manipulation spécifique à la vue et à l'événement. En personnalisant nos objets JavaScript pour les instancier en parallèle avec nos vues, nous pouvons établir une relation dynamique entre les deux - une relation de bon goût, facile à parcourir, simple à gérer et parfaite pour l'expansion. la vue s'agrandit ou change, créant une relation perméable et extensible entre le balisage et les scripts.

En utilisant un prototype d'objet, nous pouvons maintenir un contexte précis sur l'objet de script de notre vue et développer cet objet avec un état d'esprit de développement répétitif. Nous pouvons ensuite reproduire ce format via nos vues partielles, ce qui nous fait gagner du temps, de l'énergie du cerveau et des risques de bugs et de comportements inattendus..