Cet article traite de la création d'un composant Switch avec RiotJS en utilisant BeerCSS. Avant de commencer, assurez-vous d'avoir une application de base Riot, ou lisez mes articles précédent.
N'hésitez pas à vous référer à la documentation de Riot si nécessaire: https://riot.js.org/documentation/
Quatre états de Switch existent : coché, non coché, désactivé et mixte (voir la capture d'écran suivante). L'objectif est de créer un composant Switch avec le design BeerCSS et d'écouter les événements de changement.
Base du Composant Switch
Tout d'abord, créez un nouveau fichier nommé c-switch.riot
dans le dossier des composants. Le c-
signifie "composant", une convention de nommage utile et une bonne pratique.
Dans ./components/c-switch.riot
, écrivez le HTML suivant (Le CSS a été trouvé dans la documentation BeerCSS) :
<c-switch>
<label class="
switch
{ props?.icon ? 'icon' : ''}
">
<input type="checkbox" value={ props?.value ? true : false } checked={ props?.value } disabled={ props?.disabled }>
<span>
<i if={ props?.icon }>{ props.icon }</i>
</span>
</label>
</c-switch>
Décomposons le code :
- Les balises
<c-switch>
et</c-switch>
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<label>
comme balise racine ou redéfinir les balises HTML natives est une mauvaise pratique, donc commencer parc-
est un bon nommage. - Pour activer l'attribut
checked
,props.value
doit être présent et être vrai. - Derrière le switch, il utilise une balise input comme "case à cocher". Note importante: value et checked sont deux attributs différents ; le composant unifie les deux valeurs.
- L'élément est désactivé si l'attribut
props.disabled
existe et que la valeur est true. - Une icône personnalisée peut être affichée sur le switch ; l'attribut HTML
props.icon
doit exister et il ajoutera une classe icon et une balise<i>icon_name</i>
.
Enfin, instanciez le c-switch.riot dans une page index.riot:
<index-riot>
<div style="width:600px;padding:20px;">
<h4 style="margin-bottom:20px">Riot + BeerCSS</h4>
<c-switch onclick={ clicked } value={ state.value } /><br>
<c-switch icon="wifi" value={ true } /><br>
<c-switch icon="bluetooth" disabled={ true } /><br>
<c-switch icon="dark_mode" disabled={ true } value={ true} /><br>
</div>
<script>
import cSwitch from "./components/c-switch.riot";
export default {
components: {
cSwitch
},
state: {
value: true
},
clicked (ev) {
if (ev.target.tagName === "INPUT") {
this.update({ value: !this.state.value })
}
}
}
</script>
</index-riot>
Décomposition du code :
- Le composant est importé avec
import cSwitch from "./components/c-switch.riot";
puis chargé dans l'objet Riotcomponents:{}
. - Le composant est instancié avec
<c-switch />
dans le HTML. Ajoutez l'attribut "icon" pour afficher une Google Material Icon, comme<c-switch icon="home" />
. - L'état du switch est stocké dans l'objet d'état Riot
state: { value: true }
. "True" est la valeur par défaut. - Pour écouter un événement de clic ou de changement, l'attribut
onclick={}
etonchange={}
doivent être lié à une fonction locale. Dans notre cas, il déclenche la fonctionclicked
. - Lors du clic,
state.value
est mis à jour à son opposé avecthis.update({ value: !this.state.value })
. - Un problème important survient : l'événement de clic est émis deux fois ! L'expression
if (ev.target.tagName === "INPUT")
accepte un seul événement.
Capture d'écran du HTML généré :
Corriger le problème du Switch : arrêter l'événement de double-clic
Comme mentionné dans la section précédente, l'événement click
est déclenché deux fois. Le problème est que cliquer sur l'étiquette déclenche un clic à la fois sur la balise <c-switch>
et sur l'entrée enfant du switch <input type="checkbox">
.
La solution consiste à arrêter la propagation de l'événement à l'intérieur du composant et à réémettre l'événement une seule fois. À ce moment-là, je prends l'opportunité de changer la valeur booléenne en son opposé : le HTML parent recevra un événement de changement avec la valeur correcte.
- l'événement
change
émettrue
si l'entrée est cochée. - l'événement change émet
false
si l'entrée est décochée.
Le c-switch.riot mis à jour :
<c-switch>
<label
class="
switch
{ props?.icon ? 'icon' : ''}
"
onclick={ clicked }
>
<input type="checkbox" value={ props?.value ? true : false } checked={ props?.value } disabled={ props?.disabled }>
<span>
<i if={ props?.icon }>{ props.icon }</i>
</span>
</label>
<script>
export default {
clicked (e) {
e.preventDefault();
e.stopPropagation();
this.root.value = this.props.value === true || this.props.value === "true" ? false : true;
this.root.dispatchEvent(new Event('click'));
this.root.dispatchEvent(new Event('change'));
}
}
</script>
</c-switch>
Décomposition du code :
- Si un clic se produit sur la balise
<label>
, l'événement de clic n'est pas propagé et est annulé, grâce àe.preventDefault();
ete.stopPropagation();
. - La valeur de l'entrée du switch prend son opposé.
- Les événements
click
etchange
sont réémis grâce àdispatchEvent
.
La mise à jour de state.value
sur le composant parent index.riot peut être simplifiée:
<index-riot>
<div style="width:600px;padding:20px;">
<h4 style="margin-bottom:20px">Riot + BeerCSS</h4>
<c-switch changed={ changed } value={ state.value } /><br>
</div>
<script>
import cSwitch from "./components/c-switch.riot";
export default {
components: {
cSwitch
},
state: {
value: true
},
changed (ev) {
this.update({ value: ev.target.value })
}
}
</script>
</index-riot>
Maintenant, state.value
prend la valeur de l'événement change
, et la valeur de l'événement reflète toujours l'état actuel du switch. Enfin, l'événement de clic n'est déclenché qu'une seule fois.
Conseils pour simplifier encore plus : Il n'est pas nécessaire de créer une fonction "changed", une seule ligne suffit pour mettre à jour la valeur:
<c-switch changed={ (ev) => update({ value: ev.target.value }) } value={ state.value } /><br>
Test du Composant Switch
Il existe deux méthodes pour tester le composant Switch, et elles sont 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 Switch Riot en utilisant BeerCSS. Le code source du switch est disponible sur Github :
https://github.com/steevepay/riot-beercss/blob/main/components/c-switch.riot
N'hésitez pas à commenter si vous avez des questions ou besoin d'aide concernant RiotJS.
Passez une excellente journée ! Santé 🍻
Top comments (0)