Créer un site de plusieurs pages avec Meteor

Comme pour toute application Web, la création de sites de plusieurs pages nécessite un ensemble d’outils spécialisés. Dans cet article, nous allons voir comment développer une bibliothèque qui non seulement puisse différencier les différents URI, mais aussi qui exploite les principales fonctionnalités de Meteor..


Fonctionnalités prévues de la bibliothèque

Chaque fois que je dois développer une bibliothèque spécifique et ciblée comme celle-ci, j'aime commencer par le résultat de, comment puis-je que cela fonctionne?

Nous pouvons donc commencer par écrire certaines des fonctionnalités que nous aimerions avoir:

  • La possibilité de charger différentes pages en fonction de l'URI
  • Lecture des paramètres à partir de l'URI (espaces réservés)
  • Garder les pages dynamiques selon le standard Meteor

Cela a l'air bien. Maintenant, après avoir examiné ces fonctionnalités, vous pouvez penser qu'elles ressemblent beaucoup à un type de bibliothèque 'routeur' et je suis d'accord. Voyons donc comment notre bibliothèque 'routeur' fonctionnerait en action:

Router.addRoute ('/ home', 'homeTemplate'); Router.addRoute ('/ utilisateur /: nom d'utilisateur', 'profileTemplate'); Router.addRoute ('/ contact', 'contactTemplate'); Router.run ();

En conception, vous avez des concepts tels que 'forme-suit-fonction', qui utilise l'idée de tout organiser en premier et de le concevoir plus tard.

En code, je trouve souvent que le contraire est plus utile. En tant que développeurs, nous pouvons travailler dans de nombreuses directions et avoir un exemple concret de ce à quoi devrait ressembler la conception nous permet de rester concentrés et efficaces..

Maintenant que je sais ce que je veux faire, il ne reste plus qu'à la mettre en œuvre. Alors, jetons un autre regard sur nos fonctionnalités que nous avons écrites ci-dessus; nous voulons pouvoir ajouter des itinéraires et laisser Meteor rendre le modèle donné partiel. Bien entendu, les vues de Meteor fonctionnent par défaut avec les modèles du guidon, c'est pourquoi j'ai pris la décision d'en faire la dénomination de notre routeur..

La panne

Ensuite, divisons le projet en différentes sections afin de connaître les fonctionnalités sur lesquelles nous devons travailler..

  • Nous allons commencer par obtenir l'URI de la page actuelle, car nous devons faire correspondre les routes à quelque chose. Cela peut être fait assez facilement en utilisant le window.location.pathname variable, fournie par le navigateur.
  • Ensuite, nous devons avoir la possibilité d’ajouter des itinéraires. Cela aussi est assez simple maintenant que nous avons créé un exemple de code; nous aurons une fonction nommée addRoute qui acceptera un modèle de route et un nom de modèle. Cette fonction devra ensuite stocker tous ces objets route dans une sorte de tableau.
  • Avec l'URI actuel et un tableau d'itinéraires stockés, nous aurons besoin d'une méthode pour voir si elles correspondent.
  • Enfin et surtout, nous devrons choisir un itinéraire correspondant et afficher le modèle associé..

Si tout va bien, vous pouvez voir qu'en énonçant les exigences, cela aide vraiment à rationaliser la phase de planification. Nous sommes maintenant prêts à intervenir.


Mise en place

Pour commencer, créons un nouveau projet Meteor, je vais nommer le mien 'routeurdemo'. Maintenant, à l'intérieur, nous allons créer un dossier nommé 'lib'dans un autre dossier nommé'client':

météore créer routerdemo cd routerdemo mkdir -p client / lib

Ensuite, créez un fichier nommé 'routeur.js'à l'intérieur du nouvellement créé lib dossier. La raison pour laquelle nous la collonsclient', c’est que le serveur n’a pas accès à la window.location.pathname variable et en tant que tel, ne fonctionnera pas avec notre routeur. Mettre des choses dans un dossier nommé 'client'assure qu'ils ne seront exécutés que du côté client.

Maintenant dans le routeur.js fichier que vous venez de créer, installons un échafaudage:

//////////////////////////// // Routeur /////////////////////// ///// Router = uri: / * URL actuelle * /, routes: [], addRoute: / * fonction pour ajouter une route * /, getMatchingRoute: / * fonction pour obtenir la route correspondante * /, exécutez: / * fonction pour afficher le modèle de l'itinéraire correspondant * /;

Je pense que c'est un très bon échafaudage, j'ai même rempli le code du tableau d'itinéraires et ajouté quelques commentaires (progrès!). Maintenant, pour développer plus avant notre bibliothèque, nous devons discuter de la manière dont nous allons associer ces itinéraires..


Itinéraires correspondants

Ce n'est pas aussi simple que currentRoute === route, comme nous avons affaire à des espaces réservés dynamiques. Nous voulons un itinéraire pour '/identifiant d'utilisateur'faire correspondre l'URI de'/ utilisateur / 42' etc.

Pour ce faire, nous allons devoir diviser l'URI et faire un peu plus d'analyse en profondeur. Maintenant, certaines personnes pourraient penser à utiliser une regex, mais c'est un peu exagéré si vous me le demandez. Une approche beaucoup plus simple consisterait à diviser les segments et à s’assurer que les deux itinéraires ont le même nombre de segments, et à ce que les parties de l’itinéraire qui ne sont pas des espaces réservés fassent la correspondance..

Ceci peut être facilement réalisé en scindant l’URI partout où il y a une barre oblique ('/'), en utilisant le .Divisé méthode. Donc, notre première vérification ferait en sorte que les deux itinéraires ont le même nombre de segments.

Si la route est '/identifiant d'utilisateur'et nous obtenons un URI'/ profil / 42 / foo / bar', nous n’avons même pas besoin de vérifier davantage, l’un a deux segments et l’autre en a quatre, ce qui semble être un bon contrôle primaire. La prochaine chose que nous pouvons faire est de filtrer les listes et d’assurer la correspondance de chaque élément qui n’est pas un paramètre fictif. Si ces deux vérifications sont vraies, nous savons que la route correspond.

Définition de la variable URI

Commençons donc avec le réglage de la uri variable:

uri: _.compact (window.location.pathname.split ("/")),

Dans le code ci-dessus, nous fractionnons le tableau en barres obliques et transformons la chaîne en un tableau de segments. Ensuite, nous utilisons Underscore compact Pour supprimer tous les éléments vides de la liste, ceux-ci peuvent être provoqués par une barre oblique au début ou par une personne qui utilise deux barres obliques par erreur. En faisant cela, notre système sera beaucoup plus indulgent.

Ajout d'itinéraires

Ensuite, nous devons créer la fonction pour ajouter une route, il s’agit d’un processus assez similaire, mais comme nous allons faire correspondre les espaces réservés ultérieurement, nous allons stocker non seulement les segments et le nom du modèle, mais aussi les index pour les espaces réservés ainsi.

Voici la fonction terminée:

addRoute: fonction (route, modèle) var segments = _.compact (route.split ("/")); var espaces réservés = _.reduce (segments, fonction (currentArr, pièce, index) if (pièce.substr (0, 1) === ":") currentArr.push (index); segments [index] = pièce. substr (1); return currentArr;, []); this.routes.push (route: segments, template: template, placeholderIndexes: placeholders); ,

Nous commençons par diviser la route en segments, comme nous l'avons fait pour l'URI, mais cette fois-ci, nous devons également stocker les index des espaces réservés pour référence future, en utilisant les caractères Underscore. réduire méthode.

Pour l'ignorant, le réduire la fonction est similaire à la chaque méthode, il passe également en revue tous les éléments d’une liste, à la différence près, il transmet tout ce que chaque itération renvoie à l’élément suivant, pour finalement renvoyer les résultats à la variable donnée. Nous commençons avec un tableau vide (le 3ème paramètre) et nous ajoutons chaque index au fur et à mesure que nous les trouvons et le transmettons jusqu'à ce qu'il soit finalement renvoyé à la liste. espaces réservés variable.

La prochaine chose que vous verrez ici, c'est que nous renommons les segments qui sont des espaces réservés et supprimons le côlon. Nous le faisons uniquement pour des raisons esthétiques. Par la suite, cela facilitera la référence dans les modèles..

Enfin, nous transmettons les nouvelles données à notre tableau de routes, créé précédemment..

Faire correspondre une route à un URI

L'étape suivante consiste à filtrer dans la liste et à rechercher un itinéraire correspondant à l'URI actuel..

Voici la fonction complète:

getMatchingRoute: function () for (var i dans this.routes) var route = this.routes [i]; var data = ; if (route.segments.length === this.uri.length) var match = _.every (route.segments, fonction (seg, i) if (_.contains (route.placeholderIndexes, i)) data [seg] = this.uri [i]; return true; else return seg === this.uri [i];, cela); if (match) return data: data, template: route.template // pas de correspondance (ajouter 404 ou template par défaut peut-être?) return false; ,

Nous faisons pas mal de choses ici, alors parcourons-les. Nous commençons par parcourir le tableau d'itinéraires, puis nous affectons l'itinéraire actuel à une variable, ainsi qu'à un objet de données vide pour stocker les espaces réservés..

Ensuite, nous vérifions pour nous assurer que les deux itinéraires ont le même nombre de segments. Sinon, nous passons simplement à l’itinéraire suivant. S'ils ont le même nombre de composants, nous devons vérifier si les segments correspondent, vous pouvez le faire avec Underscore '_.chaque' une fonction. Cette fonction est encore comme_.chaque'méthode, sauf qu'il renvoie un booléen. La façon dont cela fonctionne est que la fonction sera exécutée pour chaque élément du tableau. S'ils retournent tous la valeur true, la fonction retournera la valeur true, sinon, elle retournera la valeur false, elle est donc parfaite pour effectuer des opérations comme celle-ci, où nous devons vérifier chaque segment..

Maintenant, le contrôle que nous effectuons est assez facile, si c'est un espace réservé, alors il convient automatiquement, puisqu'un espace réservé peut être égal à n'importe quelle valeur. Si ce n'est pas un espace réservé, nous nous assurons simplement que les deux segments correspondent, assez simple.

Afin de vérifier s’il s’agit ou non d’un espace réservé, nous passons l’index des segments en cours (stocké dans 'je') à Underscore _.contient fonction, qui vérifiera sa valeur.

Maintenant, vous vous demandez peut-être quelle est la première ligne de cette 'si'instruction est en train de se faire, eh bien, il stocke le segment dans le tableau de données sous le nom d'espace réservé indiqué. Alors, disons par exemple que vous aviez un itinéraire de '/Nom d'utilisateur'et l'URI actuel est'/ utilisateur / bob', cette ligne ajoutera une propriété à l'objet de données appelée'prénom'et passez une valeur de bob.

Le reste est assez évident, nous passons vrai ou faux, selon les circonstances, et le résultat est stocké dans 'rencontre'. Si match est true, nous retournons les données avec le nom du modèle, et s'il n'y a pas de correspondance, nous renvoyons false. Et c'est tout pour notre getMatchingRoute méthode.

Jusqu'à présent, nous pouvons obtenir l'URI actuel, ajouter des itinéraires et trouver un itinéraire correspondant. Il ne reste plus qu'à afficher le bon itinéraire. Pour cela, nous devons écrire le 'courir' méthode.


Affichage du modèle

Meteor utilise un guidon pour les modèles et stocke tous les modèles dans une variable, nommée de manière appropriée, 'Modèle'. Maintenant, si vous connaissez le guidon, alors vous savez que ces modèles ne sont que des fonctions, et en les appelant (en leur transmettant éventuellement des données), nous récupérons le code HTML du modèle..

Maintenant, appeler ces fonctions pour obtenir le code HTML du modèle fonctionnerait bien, mais ce n'est pas très semblable à Meteor, car nous en arriverions à un site Web statique normal. Heureusement, l'ajout du comportement dynamique est plus facile que vous ne le pensez, tout ce que nous avons à faire est d'envelopper l'appel de fonction dans un 'Meteor.render' appel. En le mettant dans cette fonction, il réagira aux changements dans les données et le gardera en direct.

La méthode de la course

Pour cette raison, l’exécution du routeur est très simple, créons la méthode d’exécution:

run: function () var route = this.getMatchingRoute (); if (route) var fragment = Meteor.render (function () if (Modèle [route.template]!! = = non défini) retour Modèle [route.template] (route.data);); document.body.appendChild (fragment);  else // 404

Nous commençons par obtenir l'itinéraire correspondant, en utilisant le getMatchingRoute fonction que nous venons d'écrire, nous nous assurons alors qu'il y a une correspondance, et finalement nous utilisons un autre déclaration pour gérer l'affichage d'un 404.

Dans la déclaration if, nous appelons Meteor.render et à l'intérieur, nous vérifions et appelons le modèle renvoyé, en lui transmettant les données des espaces réservés. Cette fonction retournera un fragment HTML, que nous pourrons ensuite simplement ajouter au corps du document..

Donc, avec environ 60 lignes de code, nous avons terminé notre routeur.

Le tester

La prochaine étape consiste à le tester. Je vais utiliser le même code que celui que nous avons écrit plus tôt lors de la planification de ce projet, car ce sera une bonne mesure de savoir si nous avons accompli, ce que nous voulions accomplir. Ajoutons un fichier nommé main.js à l'intérieur de client dossier et ajouter ce qui suit:

Meteor.startup (function () Router.addRoute ('/ home', 'homeTemplate'); Router.addRoute ('/ utilisateur /: nom d'utilisateur', 'profileTemplate'); Router.addRoute ('/ contact', 'contactTemplate '); Router.run (););

Dans le code ci-dessus, nous devons d’abord nous assurer que nos modèles et notre corps seront disponibles avant d’essayer de travailler avec notre routeur. Nous faisons cela en enveloppant tout notre code à l'intérieur de la Meteor.startup appel de méthode. Cela garantira que tout est prêt, et à l'intérieur de la Commencez méthode, nous pouvons ensuite ajouter nos routes et exécuter le routeur.

Création de nos modèles

Créons maintenant quelques modèles, cela peut être fait n’importe où, vous pouvez créer un sous-dossier dans le client dossier nommé templates et créez un fichier HTML distinct pour chacun, mais comme il s’agit de modèles courts et à titre d’exemple, je vais les regrouper dans un fichier nommé 'templates.html' à l'intérieur de 'client'dossier:

  

Le premier modèle est assez basique, il contient juste un peu de code HTML pour l'en-tête de la page d'accueil. Le deuxième modèle est très similaire au premier modèle, mais cette fois nous utilisons le Nom d'utilisateur paramètre de route. Maintenant, le dernier modèle utilise également un espace réservé, mais son itinéraire n'a pas le twitterName segment. En effet, les espaces réservés standard de Meteor continueront de fonctionner et fonctionneront de manière réactive..

De retour à l'intérieur du client dossier, créons maintenant un fichier nommé 'templates.js', pour déclarer l'espace réservé au contact.

Template.contactTemplate.twitterName = function () Session.setDefault ('twitter_name', '@gabrielmanricks'); return Session.get ('twitter_name'); 

Vous auriez pu simplement renvoyer une chaîne, mais je voulais démontrer que tout est encore réactif. La dernière étape consiste à supprimer les fichiers html et js par défaut du répertoire racine (dans mon cas, ils sont nommés routerdemo.html et routerdemo.js). Ceci fait, démarrez le serveur Meteor et accédez aux routes indiquées..

Essayez d'aller '/maison' ou 'utilisateur / gmanricks' ou '/contact'et ils devraient tous travailler pour vous comme prévu. Une autre chose est que, puisque nous avons stocké le nom Twitter dans Session, nous pouvons simplement ouvrir la console du navigateur sur la page de contact et entrer:

Session.set ('twitter_name', '@nettuts');

Et vous verrez que la page sera mise à jour en temps réel!


Résumé

Dans cet article, nous avons construit une bibliothèque de routeurs de base, tout en lui apportant une touche Meteor. Nous avons couvert beaucoup de concepts de base et, en fin de compte, beaucoup de concepts Underscore..

En fin de compte, j'espère que j'ai bien compris qu'il n'y a pas de véritable "magie" ici. Il s’agit vraiment de mettre en œuvre ce dont vous avez besoin, par opposition à ce que vous pouvez.

Merci d'avoir lu, j'espère que vous avez apprécié. Comme toujours, si vous avez des questions, vous pouvez les laisser ci-dessous ou me les poser sur le NetRC IRC ou sur Twitter..

Remarque: Si vous souhaitez en savoir plus sur Meteor, je viens de publier mon nouveau livre, qui détaille le processus de création d'une application, de sa conception et sa planification à sa sécurisation et à son déploiement. Vous pouvez prendre le livre au format ebook ainsi que sous couverture souple d'Amazon.