Cet article traite de la création d'un composant de menu avec RiotJS, en utilisant le CSS Material Design BeerCSS. Avant de commencer, assurez-vous d'avoir une application Riot, ou lisez mes articles précédents de la série.
Je suppose que vous avez une compréhension fondamentale de Riot ; cependant, n'hésitez pas à vous référer à la documentation si nécessaire : https://riot.js.org/documentation/
Un menu s'ouvre lors de l'interaction avec un élément (comme une icône, un bouton ou un champ de saisie) ou lorsque les utilisateurs effectuent une action spécifique. Le menu affiche une liste de choix sur une surface temporaire, permettant aux utilisateurs de faire une sélection pour exécuter des actions.
Base du composant de menu
L'objectif est de créer une application Riot avec un menu apparaissant lorsqu'un bouton est cliqué, de le masquer lorsqu'un élément est cliqué, et d'exécuter une action. Bonus : Masquer le menu lorsqu'un clic se produit en dehors du composant.
Pour afficher un menu lorsqu'un bouton est cliqué : Le menu fait partie du composant Button
, en tant que Slot. La balise <slot>
de Riot injecte des modèles HTML personnalisés dans un composant enfant à partir de son parent.
Le code suivant du composant Bouton est utilisé pour rendre le menu visible, situé dans ./components/c-button.riot. Le HTML provient de la documentation BeerCSS et j'ai ajouté la syntaxe RiotJS pour la logique :
<c-button>
<button>
<span><slot></slot></span>
<i icon={ props?.icon }>props?.icon</i>
<slot name="menu"></slot>
</button>
</c-button>
Cliquez ici pour en apprendre plus sur créer un composant Button
Décomposons le code :
- Les balises
<c-button>
et</c-button>
définissent une balise racine personnalisée, portant le même nom que le fichier. Vous devez l'écrire ; sinon, cela pourrait créer des résultats inattendus. Utiliser la balise<button></button>
comme balise racine ou redéfinir des balises HTML natives est une mauvaise pratique ; commencer parc-
est une bonne convention. - L'étiquette du bouton est passée en tant que Slot.
- Le menu est passé en tant que Slot nommé "Menu" :
<slot name="menu"></slot>
. - Une icône optionnelle peut être passée en tant qu'attribut si
props.icon
existe ; elle affichera une icône Google Font.
Enfin, chargez et instanciez c-button.riot dans une page principale nommée index.riot:
<index-riot>
<div style="width:600px;padding:20px;">
<c-button icon="arrow_drop_down" onclick={ (ev) => toggle(ev, 'button') } onfocusout={ () => update({ active: false })}>
Menu
<template slot="menu">
<menu class="no-wrap{ state.active === true ? ' active' : ''}">
<a class="row" onclick={ (ev) => toggle(ev, 'item1') }>
<i>visibility</i>
<span class="max">Item 1</span>
</a>
<a class="row" onclick={ (ev) => toggle(ev, 'item2') }>
<i>content_copy</i>
<span class="max">Item 2</span>
<span>⌘C</span>
</a>
<a class="row" onclick={ (ev) => toggle(ev, 'item3') }>
<i>edit</i>
<span class="max">Item 3</span>
</a>
<div class="small-divider"></div>
<a class="row" onclick={ (ev) => toggle(ev, 'item4') }>
<img class="circle tiny" src="../favicon.png">
<div class="max">
<div>Item 4</div>
<label>Some text here</label>
</div>
</a>
</menu>
</template>
</c-button>
</div>
<script>
import cButton from "../components/c-button.riot"
export default {
components: {
cButton
},
state: {
active: false
},
toggle (ev, origin) {
ev.stopPropagation();
ev.preventDefault();
// Hide the menu
this.update({ active: this.state.active === true ? false : true })
if (origin === 'item1') {
// do something
} else if (origin === 'item2') {
// do something else
}
}
}
</script>
</index-riot>
Code Source: https://github.com/steevepay/riot-beercss/blob/main/examples/index.menu.riot
Détails du code :
- Le composant est importé avec
import cButton from "./components/c-button.riot";
puis chargé dans l'objet Riotcomponents:{}
. - Le composant button est instancié avec
<c-button>
dans le HTML. - Le menu est passé en tant que slot dans une balise HTML
<menu>
. - Chaque élément de la liste a l'architecture suivante, enveloppée dans une balise
<a>
avec une icône et une étiquette :<a class="row"><i>icon</i><span class="max">Label</span></a>
. - L'état du menu est stocké dans un objet Riot
state:{}
, via la variable booléennestate.active
. - Pour rendre le menu visible, le menu doit contenir la classe "active" : Lorsque
state.active
est vrai (true), il applique la classe "active" ; sinon, il n'applique rien. - Lorsqu'un clic se produit sur le bouton, la fonction
toggle
est exécutée pour attribuer le booléen opposé àstate.active
. En même temps, une chaîne est passée à la fonctiontoggle
pour définir l'origine du clic, soit :button
, soit un élément du menu. Grâce à l'origine, une fonction spécifique peut être exécutée : appels API, ouverture d'une page, et toute autre action ! - Lorsqu'un clic se produit en dehors du menu, l'événement "focusout" est capturé pour masquer le menu avec l'expression :
onfocusout={ () => update({ active: false })}
. - Un élément du menu peut avoir un style différent, par exemple, le dernier élément de la liste affiche une image au lieu d'une icône, suivie d'un titre et d'un sous-titre. Trouvez tous les exemples de menu sur la documentation des menus BeerCSS.
Test du composant de menu
Il existe deux méthodes pour tester le composant de menu, couvertes dans deux articles différents :
- Test avec Vitest et Riot-SSR dans un environnement Node
- Test avec Vitest dans un environnement JsDom
Conclusion
Voilà 🎉 Nous avons créé un composant de menu Riot en utilisant des éléments Material Design avec BeerCSS. Le code source de la barre de menu est disponible sur Github : https://github.com/steevepay/riot-beercss/blob/main/components/c-menu.riot
Passez une excellente journée ! Santé 🍻
Top comments (0)