DEV Community

Steeve
Steeve

Posted on

Composant Menu avec RiotJS

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.

Example of a Menu opening when a button is clicked

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.

GIF of a Menu Component made with RiotJS and BeerCSS

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>
Enter fullscreen mode Exit fullscreen mode

Cliquez ici pour en apprendre plus sur créer un composant Button

Décomposons le code :

  1. 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 par c- est une bonne convention.
  2. L'étiquette du bouton est passée en tant que Slot.
  3. Le menu est passé en tant que Slot nommé "Menu" : <slot name="menu"></slot>.
  4. 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>
Enter fullscreen mode Exit fullscreen mode

Code Source: https://github.com/steevepay/riot-beercss/blob/main/examples/index.menu.riot

Détails du code :

  1. Le composant est importé avec import cButton from "./components/c-button.riot"; puis chargé dans l'objet Riot components:{}.
  2. Le composant button est instancié avec <c-button> dans le HTML.
  3. Le menu est passé en tant que slot dans une balise HTML <menu>.
  4. 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>.
  5. L'état du menu est stocké dans un objet Riot state:{}, via la variable booléenne state.active.
  6. 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.
  7. 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 fonction toggle 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 !
  8. 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 })}.
  9. 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 :

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)