Introduction au cadre de stimulation

Il existe de nombreux frameworks JavaScript. Parfois, je commence même à penser que je suis le seul à ne pas avoir encore créé de cadre. Certaines solutions, telles que Angular, sont volumineuses et complexes, alors que d'autres, telles que Backbone (qui est plus une bibliothèque que un framework), sont assez simples et ne fournissent que quelques outils pour accélérer le processus de développement..

Dans l'article d'aujourd'hui, j'aimerais vous présenter un tout nouveau cadre appelé Stimulus. Il a été créé par une équipe Basecamp dirigée par David Heinemeier Hansson, un développeur populaire qui fut le père de Ruby on Rails..

Stimulus est un petit cadre qui n’a jamais été conçu pour devenir grand. Il a sa propre philosophie et son attitude vis-à-vis du développement en amont, ce que certains programmeurs pourraient aimer ou non. Stimulus est jeune, mais la version 1 a déjà été publiée et devrait donc être utilisée en toute sécurité. J'ai pas mal joué avec ce framework et j'ai beaucoup aimé sa simplicité et son élégance. J'espère que vous l'apprécierez aussi!

Dans cet article, nous aborderons les bases de Stimulus lors de la création d'une application d'une page avec chargement de données asynchrone, événements, persistance d'état et autres tâches courantes..

Le code source peut être trouvé sur GitHub.

Introduction à la stimulation

Stimulus a été créé par les développeurs de Basecamp. Au lieu de créer des applications JavaScript d'une seule page, ils ont décidé de choisir un monolithe majestueux alimenté par Turbolinks et du JavaScript. Ce code JavaScript a évolué dans un cadre petit et modeste qui ne vous oblige pas à passer des heures et des heures à apprendre tous ses concepts et ses mises en garde..

Stimulus est principalement destiné à s’attacher aux éléments DOM existants et à les utiliser d’une manière ou d’une autre. Toutefois, il est également possible de rendre dynamiquement le contenu. Globalement, ce cadre est assez différent des autres solutions populaires, par exemple, il persiste dans un état HTML, pas dans des objets JavaScript. Certains développeurs le trouveront peut-être gênant, mais laissez une chance à Stimulus, car cela pourrait vous surprendre..

Le cadre ne contient que trois concepts principaux, à savoir:

  • Contrôleurs: Classes JS avec certaines méthodes et callbacks qui s'attachent au DOM. L'attachement se produit lorsqu'un contrôleur de données L'attribut "magique" apparaît sur la page. La documentation explique que cet attribut est un pont entre HTML et JavaScript, tout comme les classes servent de ponts entre HTML et CSS. Un contrôleur peut être attaché à plusieurs éléments et un élément peut être alimenté par plusieurs contrôleurs.
  • actes: méthodes à appeler pour des événements spécifiques. Ils sont définis en particulier action de données les attributs.
  • Les cibles: éléments importants qui peuvent être facilement consultés et manipulés. Ils sont spécifiés avec l'aide de cible de données les attributs.

Comme vous pouvez le constater, les attributs répertoriés ci-dessus vous permettent de séparer le contenu de la logique de comportement de manière très simple et naturelle. Plus tard dans cet article, nous verrons tous ces concepts en action et constaterons à quel point il est facile de lire un document HTML et de comprendre ce qui se passe..

Démarrer une application de stimulation

Stimulus peut être facilement installé en tant que package NPM ou chargé directement via le scénario balise comme expliqué dans la documentation. Notez également que, par défaut, cette infrastructure s’intègre au gestionnaire d’actifs Webpack, qui prend en charge des goodies tels que le chargement automatique des contrôleurs. Vous êtes libre d'utiliser n'importe quel autre système de build, mais dans ce cas, il vous faudra encore du travail..

Le moyen le plus rapide de démarrer avec Stimulus consiste à utiliser ce projet de démarrage auquel le serveur Web Express et Babel sont déjà connectés. Cela dépend également du fil, alors assurez-vous de l'installer. Pour cloner le projet et installer toutes ses dépendances, exécutez:

git clone https://github.com/stimulusjs/stimulus-starter.git installation d'un fil de démarrage pour stimulus

Si vous préférez ne rien installer localement, vous pouvez remixer ce projet sur Glitch et procéder au codage directement dans votre navigateur..

Génial - nous sommes tous prêts et pouvons passer à la section suivante!

Du balisage

Supposons que nous créons une petite application d'une page qui présente une liste des employés et charge des informations telles que leur nom, leur photo, leur poste, leur salaire, leur date de naissance, etc..

Commençons par la liste des employés. Tout le balisage que nous allons écrire doit être placé à l'intérieur du public / index.html fichier, qui a déjà un code HTML très minimal. Pour le moment, nous allons coder en dur tous nos employés de la manière suivante:

 

Nos employés

  • John Doe
  • Alice Smith
  • Will Brown
  • Ann Gray

Agréable! Ajoutons maintenant un trait de magie du stimulus.

Créer un contrôleur

Comme l'explique la documentation officielle, Stimulus a pour objectif principal de connecter des objets JavaScript (appelés contrôleurs) aux éléments DOM. Les contrôleurs donneront ensuite vie à la page. Par convention, les noms des contrôleurs doivent se terminer par un _manette postfix (qui devrait être très familier aux développeurs Rails).

Il existe déjà un répertoire pour les contrôleurs, appelé src / contrôleurs. À l'intérieur, vous trouverez un  hello_controller.js fichier qui définit une classe vide:

import Controller de la classe par défaut d'exportation "stimulus" étend Controller  

Renommons ce fichier en employee_controller.js. Nous n’avons pas besoin de le demander spécifiquement car les contrôleurs sont chargés automatiquement grâce aux lignes de code suivantes dans le répertoire. src / index.js fichier:

const application = Application.start () const contexte = require.context ("./ controllers", true, /\.js$/) application.load (definitionsFromContext (context))

L'étape suivante consiste à connecter notre contrôleur au DOM. Pour ce faire, définissez un contrôleur de données attribuer et lui attribuer un identifiant (qui est employés dans notre cas):

C'est tout! Le contrôleur est maintenant attaché au DOM.

Rappel du cycle de vie

Une chose importante à savoir sur les contrôleurs est qu’ils disposent de trois rappels de cycle de vie qui sont déclenchés dans des conditions spécifiques:

  • initialiser: ce rappel ne se produit qu'une fois, lorsque le contrôleur est instancié.
  • relier: se déclenche chaque fois que nous connectons le contrôleur à l'élément DOM. Comme un contrôleur peut être connecté à plusieurs éléments de la page, ce rappel peut s'exécuter plusieurs fois..
  • déconnecter: comme vous l'avez probablement deviné, ce rappel s'exécute chaque fois que le contrôleur se déconnecte de l'élément DOM.

Rien de complexe, non? Profitons de la initialiser() et relier() callbacks pour vous assurer que notre contrôleur fonctionne réellement:

// La classe par défaut d'exportation // src / controllers / employee_controller.js étend le contrôleur initialize () console.log ('initialisé') console.log (this) connect () console.log ('connecté') console.log ( ce)  

Ensuite, démarrez le serveur en lançant:

début de fil

Aller vers http: // localhost: 9000. Ouvrez la console de votre navigateur et assurez-vous que les deux messages sont affichés. Cela signifie que tout fonctionne comme prévu!

Ajout d'événements

Le prochain concept de stimulation est événements. Les événements sont utilisés pour répondre aux différentes actions de l'utilisateur sur la page: cliquer, survoler, faire la mise au point, etc. Stimulus n'essaie pas de réinventer un vélo et son système d'événements est basé sur des événements JS génériques..

Par exemple, lions un événement de clic à nos employés. Chaque fois que cet événement se produit, je voudrais appeler le encore inexistant choisir() méthode du employés_contrôleur:

 
  • employés # choisir "> John Doe
  • employés # choisir "> Alice Smith
  • employés # choisir "> Will Brown
  • employés # choisir "> Ann Grey

Probablement, vous pouvez comprendre ce qui se passe ici par vous-même.

  • action de données est l'attribut spécial qui lie un événement à l'élément et explique quelle action doit être appelée.
  • Cliquez sur, bien sûr, est le nom de l'événement.
  • employés est l'identifiant de notre contrôleur.
  • choisir est le nom de la méthode que nous aimerions appeler.

Puisque Cliquez sur est l'événement le plus commun, il peut être omis en toute sécurité:

  • John Doe
  • Dans ce cas, Cliquez sur sera utilisé implicitement.

    Ensuite, codons le choisir() méthode. Je ne veux pas que l’action par défaut se produise (c’est-à-dire ouvrir une nouvelle page spécifiée dans le href attribut), alors évitons-le:

    // src / controllers / employee_controller.js // callbacks here… choisissez (e) e.preventDefault () console.log (this) console.log (e)

    e est l'objet événement spécial qui contient des informations complètes sur l'événement déclenché. Notez, en passant, que ce renvoie le contrôleur lui-même, pas un lien individuel! Afin d'accéder à l'élément qui agit comme cible de l'événement, utilisez e.target.

    Rechargez la page, cliquez sur un élément de la liste et observez le résultat.!

    Travailler avec l'Etat

    Maintenant que nous avons lié un gestionnaire d'événements de clic aux employés, j'aimerais stocker la personne actuellement choisie. Pourquoi? Ayant enregistré ces informations, nous pouvons empêcher le même employé d’être sélectionné une deuxième fois. Cela nous permettra par la suite d’éviter de charger plusieurs fois la même information..

    Stimulus nous demande de conserver l'état dans l'API de données, ce qui semble tout à fait raisonnable. Tout d’abord, fournissons des identifiants arbitraires pour chaque employé utilisant le ID de données attribut:

     
    • John Doe
    • employés # choisir "> Alice Smith
    • employés # choisir "> Will Brown
    • employés # choisir "> Ann Grey

    Ensuite, nous devons récupérer l'identifiant et le conserver. L’utilisation de l’API de données est très courante avec Stimulus, c’est pourquoi this.data objet est fourni pour chaque contrôleur. Avec son aide, nous pouvons exécuter les méthodes suivantes:

    • this.data.get ('nom'): obtenir la valeur par son attribut.
    • this.data.set ('nom', valeur): définir la valeur sous un attribut.
    • this.data.has ('nom'): vérifie si l'attribut existe (retourne une valeur booléenne).

    Malheureusement, ces raccourcis ne sont pas disponibles pour les cibles des événements de clic, nous devons donc nous en tenir à getAttribute () dans leur cas:

     // src / controllers / employee_controller.js choisissez (e) e.preventDefault () this.data.set ("current-employee", e.target.getAttribute ('data-id'))

    Mais nous pouvons faire encore mieux en créant un getter et un setter pour le employé actuel:

     // src / controllers / employee_controller.js get currentEmployee () return this.data.get ("current-employee") set currentEmployee (id) if (this.currentEmployee! == id) this.data.set ("current-employee", id)

    Notez comment nous utilisons le this.currentEmployee getter et en s'assurant que l'identifiant fourni n'est pas le même que celui déjà stocké.

    Maintenant, vous pouvez réécrire le choisir() méthode de la manière suivante:

     // src / controllers / employee_controller.js choisissez (e) e.preventDefault () this.currentEmployee = e.target.getAttribute ('data-id')

    Rechargez la page pour vous assurer que tout fonctionne toujours. Vous ne remarquerez pas encore de changements visuels, mais à l'aide de l'outil Inspecteur, vous remarquerez que le ul a la données-employés-employé-actuel attribuer avec une valeur qui change lorsque vous cliquez sur les liens. le employés la partie dans le nom de l'attribut est l'identifiant du contrôleur et est ajoutée automatiquement.

    Passons maintenant à la sélection de l’employé actuellement sélectionné.

    Utilisation de cibles

    Quand un employé est sélectionné, je voudrais assigner l’élément correspondant avec un .choisi classe. Bien sûr, nous aurions peut-être résolu cette tâche en utilisant certaines fonctions de sélecteur JS, mais Stimulus fournit une solution plus simple..

    Atteindre les cibles, ce qui vous permet de marquer un ou plusieurs éléments importants sur la page. Ces éléments peuvent ensuite être facilement consultés et manipulés au besoin. Pour créer une cible, ajoutez un cible de données attribuer avec la valeur de contrôleur. nom_cible (qui s'appelle un descripteur de cible):

     
    • John Doe
    • employés # choisir "> Alice Smith
    • employés # choisir "> Will Brown
    • employés # choisir "> Ann Grey

    Maintenant, informez Stimulus de ces nouvelles cibles en définissant une nouvelle valeur statique:

    // La classe d'exportation par défaut de src / controllers / employee_controller.js s'étend au contrôleur static tasks = ["employee"] //…

    Comment pouvons-nous accéder aux cibles maintenant? C'est aussi simple que de dire this.employeeTarget (pour obtenir le premier élément) ou this.employeeTargets (pour obtenir tous les éléments):

     // src / controllers / employee_controller.js choisissez (e) e.preventDefault () this.currentEmployee = e.target.getAttribute ('data-id') console.log (this.employeeTargets) console.log (this.employeeTarget )

    Génial! Comment ces cibles peuvent-elles nous aider maintenant? Nous pouvons les utiliser pour ajouter et supprimer facilement des classes CSS en fonction de certains critères:

     // src / controllers / employee_controller.js choisissez (e) e.preventDefault () this.currentEmployee = e.target.getAttribute ('data-id') this.employeeTargets.forEach ((el, i) => el .classList.toggle ("choisi", this.currentEmployee === el.getAttribute ("data-id")))

    L’idée est simple: nous parcourons un tableau de cibles et comparons ses cibles. ID de données à celui stocké sous this.currentEmployee. Si cela correspond, l'élément se voit attribuer le .choisi classe. Sinon, cette classe est supprimée. Vous pouvez également extraire le if (this.currentEmployee! == id) état du poseur et l'utiliser dans le choisi() méthode à la place:

     // src / controllers / employee_controller.js choisissez (e) e.preventDefault () const id = e.target.getAttribute ('data-id') if (this.currentEmployee! == id) // <--- this.currentEmployee = id this.employeeTargets.forEach((el, i) => el.classList.toggle ("choisi", id === el.getAttribute ("data-id"))

    Vous cherchez bien! Enfin, nous allons fournir un style très simple pour le .choisi classe à l'intérieur du public / main.css:

    .choisi font-weight: bold; texte-décoration: aucun; curseur: par défaut; 

    Rechargez une nouvelle fois la page, cliquez sur une personne et assurez-vous que cette personne est bien mise en surbrillance..

    Chargement de données de manière asynchrone

    Notre tâche suivante consiste à charger des informations sur l'employé choisi. Dans une application réelle, vous devez configurer un fournisseur d'hébergement, un back-end optimisé avec quelque chose comme Django ou Rails, et un point de terminaison API qui répond avec un JSON contenant toutes les données nécessaires. Mais nous allons simplifier les choses et nous concentrer uniquement sur le client. Créé un employés répertoire sous le Publique dossier. Ensuite, ajoutez quatre fichiers contenant des données pour des employés individuels:

    1.json

    "nom": "John Doe", "genre": "homme", "âge": "40", "poste": "PDG", "salaire": "120 000 $ / an", "image": "https : //burst.shopifycdn.com/photos/couple-in-love-at-sunset_373x.jpg " 

    2.json

    "nom": "Alice Smith", "sexe": "femme", "âge": "32", "poste": "CTO", "salaire": "100 000 USD / an", "image": "https : //burst.shopifycdn.com/photos/woman-listening-at-team-meeting_373x.jpg " 

    3.json

    "nom": "Will Brown", "sexe": "homme", "âge": "30", "poste": "Tech Lead", "salaire": "80.000 USD / an", "image": " https://burst.shopifycdn.com/photos/casual-urban-menswear_373x.jpg " 

    4.json

    "name": "Ann Grey", "genre": "femme", "age": "25", "position": "Junior Dev", "salaire": "20.000 USD / an", "image": " https://burst.shopifycdn.com/photos/woman-using-tablet_373x.jpg " 

    Toutes les photos ont été prises à partir de la photographie gratuite de Shopify appelée Burst..

    Nos données sont prêtes et attendent d'être chargées! Pour ce faire, nous coderons un loadInfoFor () méthode:

     // src / controllers / employee_controller.js loadInfoFor (id_employé) fetch ('employés / $ id_employé .json') .then (response => response.text ()) .then (json => this.displayInfo ( json))

    Cette méthode accepte l'identifiant d'un employé et envoie une demande d'extraction asynchrone à l'URI donné. Il y a aussi deux promesses: une pour récupérer le corps et une autre pour afficher les informations chargées (nous ajouterons la méthode correspondante dans un moment).

    Utiliser cette nouvelle méthode à l'intérieur choisir():

     // src / controllers / employés_controller.js choisissez (e) e.preventDefault () const id = e.target.getAttribute ('id_données') if (this.currentEmployee! == id) this.loadInfoFor (id ) //…

    Avant de coder le displayInfo () méthode, nous avons besoin d’un élément pour rendre les données. Pourquoi ne profitons-nous pas encore des objectifs??

     

    Définir la cible:

    // La classe d'exportation par défaut de src / controllers / employee_controller.js s'étend au contrôleur static tasks = ["employee", "info"] //…

    Et maintenant, utilisez-le pour afficher toutes les informations:

     // src / controllers / employee_controller.js displayInfo (raw_json) const info = JSON.parse (raw_json) const html = '
    • Nom: $ info.name
    • Sexe: $ info.gender
    • Âge: $ info.age
    • Position: $ info.position
    • Salaire: $ info.salary
    'this.infoTarget.innerHTML = html

    Bien sûr, vous êtes libre d’employer un moteur de gabarit comme le guidon, mais pour ce cas simple, il serait probablement excessif..

    Rechargez maintenant la page et choisissez l’un des employés. Sa bio et son image devraient être chargées presque instantanément, ce qui signifie que notre application fonctionne correctement.!

    Liste dynamique des employés

    En utilisant l'approche décrite ci-dessus, nous pouvons aller encore plus loin et charger la liste des employés à la volée plutôt que de la coder en dur.

    Préparez les données à l'intérieur du public / employés.json fichier:

    ["id": "1", "name": "John Doe", "id": "2", "name": "Alice Smith", "id": "3", "name ":" Will Brown ", " id ":" 4 "," nom ":" Ann Gray "]

    Maintenant, modifiez le public / index.html fichier en supprimant la liste codée en dur et en ajoutant un données-employés-url attribut (notez que nous devons fournir le nom du contrôleur, sinon l'API de données ne fonctionnera pas):

    Dès que le contrôleur est connecté au DOM, il doit envoyer une demande d’extraction pour créer une liste d’employés. Cela signifie que le relier() callback est l'endroit idéal pour faire ceci:

     // src / controllers / employee_controller.js connect () this.loadFrom (this.data.get ('url'), this.displayEmployees)

    Je propose de créer un plus générique loadFrom () méthode qui accepte une URL pour charger des données et un rappel pour restituer ces données:

     // src / controllers / employee_controller.js loadFrom (url, rappel) fetch (url) .then (response => response.text ()) .then (json => callback.call (this, JSON.parse (json )))

    Tweak le choisir() méthode pour profiter de la loadFrom ():

     // src / controllers / employee_controller.js choisit (e) e.preventDefault () const id = e.target.getAttribute ('data-id') if (this.currentEmployee! == id) this.loadFrom (' employés / $ id .json ', this.displayInfo) // <--- this.currentEmployee = id this.employeeTargets.forEach((el, i) => el.classList.toggle ("choisi", id === el.getAttribute ("data-id"))

    displayInfo () peut également être simplifié, car JSON est maintenant analysé à l’intérieur du loadFrom ():

     // src / controllers / employee_controller.js displayInfo (info) const html = '
    • Nom: $ info.name
    • Sexe: $ info.gender
    • Âge: $ info.age
    • Position: $ info.position
    • Salaire: $ info.salary
    'this.infoTarget.innerHTML = html

    Retirer loadInfoFor () et coder le displayEmployees () méthode:

     // src / controllers / employees_controller.js displayEmployees (employés) let html = "
      "employés.pour chaque ((el) => html + = '
    • $ el.name
    • ') html + = "
    "this.element.innerHTML + = html

    C'est tout! Nous rendons maintenant notre liste d'employés de manière dynamique en fonction des données renvoyées par le serveur..

    Conclusion

    Dans cet article, nous avons présenté un cadre JavaScript modeste appelé Stimulus. Nous avons vu comment créer une nouvelle application, ajouter un contrôleur avec une multitude de callbacks et d’actions et introduire des événements et des actions. De plus, nous avons effectué un chargement de données asynchrone à l’aide de requêtes de récupération.

    Tout compte fait, c’est tout pour les bases de Stimulus: il n’attend vraiment pas que vous ayez des connaissances obscures pour la conception d’applications Web. Bien sûr, le framework aura probablement de nouvelles fonctionnalités à l’avenir, mais les développeurs ne prévoient pas de le transformer en un énorme monstre avec des centaines d’outils.. 

    Si vous souhaitez trouver d'autres exemples d'utilisation de Stimulus, vous pouvez également consulter ce petit manuel. Et si vous recherchez des ressources JavaScript supplémentaires à étudier ou à utiliser dans votre travail, consultez ce que nous avons à votre disposition sur le marché Envato.. 

    Vous avez aimé Stimulus? Seriez-vous intéressé à essayer de créer une application réelle alimentée par ce cadre? Partagez votre opinion dans les commentaires!

    Comme toujours, je vous remercie de rester avec moi et jusqu'à la prochaine fois.