Fermer

novembre 21, 2019

Créer un commutateur à bascule dans React en tant que composant réutilisable –


Dans cet article, nous allons créer un commutateur à bascule inspiré par iOS utilisant des composants React. À la fin, nous aurons construit une application de démonstration simple, React, qui utilise notre composant de commutateur à bascule personnalisé.

Nous pourrions utiliser des bibliothèques tierces à cet effet, mais la création à partir de rien nous permet de mieux comprendre le fonctionnement de notre code et nous permet de personnaliser complètement notre composant.

Les formulaires constituent un moyen essentiel d’activation des interactions entre utilisateurs. La case à cocher est traditionnellement utilisée pour collecter des données binaires – telles que yes ou no true ou false permis ou désactiver sur ou sur etc. Bien que certaines conceptions d'interface modernes s'éloignent des champs de formulaire lors de la création de commutateurs, je les garde ici. en raison de leur plus grande accessibilité.

Voici une capture d'écran du composant que nous allons construire:

 Le résultat final

Pour commencer

Nous pouvons commencer par un élément de formulaire HTML élément de formulaire d'entrée avec ses propriétés nécessaires définies:


Pour construire autour de lui, nous aurions peut-être besoin d'un

contenant une classe un et le contrôle . En ajoutant tout, on pourrait avoir quelque chose comme ceci:

Avec le temps, nous pouvons supprimer le texte de l'étiquette et utiliser la balise pour cocher ou décocher le contrôle d'entrée des cases à cocher. Dans le ajoutons deux qui nous aident à construire le support de commutateur et le commutateur à bascule lui-même:

Conversion en composant réactif

Maintenant que nous savons ce qui doit être inséré dans le code HTML, tous nous devons faire est de convertir le code HTML en un composant React. Commençons par un élément de base ici. Nous en ferons un composant de classe, puis nous le convertirons en crochets, car il est plus facile pour les nouveaux développeurs de suivre l'état que useState :

 import React, { Composant} de "réagir";

la classe ToggleSwitch étend le composant {
  render () {
    revenir (
      
);   } } export par défaut ToggleSwitch;

À ce stade, il est impossible d’avoir plusieurs curseurs d’interrupteur à bascule sur la même vue ou sur la même page en raison de la répétition de id . Nous pourrions tirer parti de la manière dont React composait, mais dans ce cas, nous utiliserons les accessoires pour renseigner de manière dynamique les valeurs:

 import React, {Component} de "reay";

la classe ToggleSwitch étend le composant {
  render () {
    revenir (
      
);   } } export par défaut ToggleSwitch;

Le nom this.props.Name va renseigner les valeurs de id nom et pour (notez qu'il est ] htmlFor dans React JS) de manière dynamique, de sorte que vous puissiez transmettre différentes valeurs au composant et en avoir plusieurs sur la même page. En outre, la balise n’a pas de balise de fin ; il est fermé dans la balise de départ, comme et c'est tout à fait correct.

Styling and CSS

J'ai récemment écrit 8 façons de styliser les composants React et nous allons utiliser SCSS ici. (que je considère comme le meilleur moyen). Notre fichier SCSS étant déjà inclus dans le script index.js de départ, il n’est pas nécessaire d’inclure un autre fichier SCSS dans le composant lui-même. Voyons d’abord comment le CSS de base est réalisé. Après cela, nous apporterons des améliorations. Voici ce que nous allons faire avec le style:

  • Par défaut, le commutateur ne fera que 75px de large et aligné verticalement dans le bloc en ligne . qu'il est en ligne avec le texte et ne pose pas de problème de mise en page.
  • Nous allons nous assurer que le contrôle n'est pas sélectionnable afin que les utilisateurs puissent le glisser-déposer.
  • Nous allons également masquer l'entrée de case à cocher d'origine. .
  • Les :: après et les :: avant doivent être conçus et créés comme des éléments permettant de les insérer dans le DOM et de le personnaliser.
  • Nous allons également ajoutez des transitions CSS pour donner un aspect cool et animé.
 .toggle-switch {
  position: relative;
  largeur: 75px;
  affichage: inline-block;
  alignement vertical: milieu;
  -webkit-user-select: aucun;
  -moz-user-select: aucun;
  -ms-user-select: none;
  text-align: left;
}
.toggle-switch-checkbox {
  affichage: aucun;
}
.toggle-switch-label {
  bloc de visualisation;
  débordement caché;
  curseur: pointeur;
  bordure: 0 solide #ccc;
  border-radius: 20px;
  marge: 0;
}
.toggle-switch-inner {
  bloc de visualisation;
  largeur: 200%;
  marge gauche: -100%;
  transition: la marge 0.3s décroît à 0;
}
.toggle-switch-inner :: avant, .toggle-switch-inner :: après {
  bloc de visualisation;
  float: gauche;
  largeur: 50%;
  hauteur: 34px;
  rembourrage: 0;
  hauteur de ligne: 34px;
  taille de police: 14px;
  Couleur blanche;
  poids de police: gras;
  taille de la boîte: boîte à bordure;
}
.toggle-switch-inner: avant {
  contenu: "oui";
  text-transform: majuscule;
  padding-left: 10px;
  couleur de fond: # f90;
  couleur: #fff;
}
.toggle-switch-disabled {
  couleur de fond: #ccc;
  curseur: non autorisé;
}
.toggle-switch-disabled :: before {
  couleur de fond: #ccc;
  curseur: non autorisé;
}
.toggle-switch-inner :: after {
  contenu: "non";
  text-transform: majuscule;
  padding-right: 10px;
  couleur de fond: #ccc;
  couleur: #fff;
  text-align: right;
}
.toggle-switch-switch {
  bloc de visualisation;
  largeur: 24px;
  marge: 5px;
  background: #fff;
  position: absolue;
  en haut: 0;
  en bas: 0;
  à droite: 40px;
  bordure: 0 solide #ccc;
  border-radius: 20px;
  transition: tous les 0.3s décrochent les 0;
}
case à cocher .toggle-switch: cochée + étiquette .toggle-switch-label .toggle-switch-inner {
  marge gauche: 0;
}
case à cocher .toggle-switch: cochée + étiquette .toggle-switch-switch .toggle-switch-switch {
  à droite: 0px;
}

Si nous examinons ceci, le "Oui" et le "Non" peuvent être envoyés ici de manière dynamique à partir du contrôle à l'aide des attributs - * de HTML5. Cela est nécessaire car ce ne sont pas toujours les mêmes valeurs "Oui" et "Non" . Rendons-le dynamique pour le moment:

 .toggle-switch-inner :: before {
  contenu: attr (data-yes);
  / * autres styles * /
}
.toggle-switch-inner :: after {
  contenu: attr (no de données);
  / * autres styles * /
}

Aussi, ce serait une bonne idée d'utiliser une version plus petite de switch, sans le texte. Ajoutons donc un peu plus de CSS à cette taille, avec des tailles minimales et supprimons le texte:

 .toggle-switch.small- commutateur {
  largeur: 40px;
}
.toggle-switch.small-switch .toggle-switch-inner: après, .toggle-switch.small-switch .toggle-switch-inner: avant {
  contenu: "";
  hauteur: 20px;
  hauteur de ligne: 20px;
}
.toggle-switch.small-switch .toggle-switch-switch {
  largeur: 16px;
  à droite: 20px;
  marge: 2px;
}

En ce qui concerne la réactivité, nous devrions modifier la taille complète. Pour une version hacky, nous allons utiliser la fonction CSS scale . Nous avons couvert ici toutes les largeurs de périphériques sensibles basées sur Bootstrap:

 @media screen et (max-width: 991px) {
  .interrupteur à bascule {
    transformer: échelle (0,9);
  }
}
Écran @média et (largeur maximale: 767px) {
  .interrupteur à bascule {
    transformer: échelle (0,825);
  }
}
Écran @média et (largeur maximale: 575 pixels) {
  .interrupteur à bascule {
    transformer: échelle (0,75);
  }
}

En convertissant le code ci-dessus en SCSS, nous obtiendrons quelque chose comme:

 .toggle-switch {
  position: relative;
  largeur: 75px;
  affichage: inline-block;
  alignement vertical: milieu;
  -webkit-user-select: aucun;
  -moz-user-select: aucun;
  -ms-user-select: none;
  text-align: left;
  & -checkbox {
    affichage: aucun;
  }
  & -label {
    bloc de visualisation;
    débordement caché;
    curseur: pointeur;
    bordure: 0 solide #ccc;
    border-radius: 20px;
    marge: 0;
  }
  & -inner {
    bloc de visualisation;
    largeur: 200%;
    marge gauche: -100%;
    transition: la marge 0.3s décroît à 0;
    &:avant,
    &:après {
      bloc de visualisation;
      float: gauche;
      largeur: 50%;
      hauteur: 34px;
      rembourrage: 0;
      hauteur de ligne: 34px;
      taille de police: 14px;
      Couleur blanche;
      poids de police: gras;
      taille de la boîte: boîte à bordure;
    }
    &:avant {
      contenu: attr (data-yes);
      text-transform: majuscule;
      padding-left: 10px;
      couleur de fond: # f90;
      couleur: #fff;
    }
  }
  &-désactivé {
    couleur de fond: #ccc;
    curseur: non autorisé;
    &:avant {
      couleur de fond: #ccc;
      curseur: non autorisé;
    }
  }
  & -inner: après {
    contenu: attr (no de données);
    text-transform: majuscule;
    padding-right: 10px;
    couleur de fond: #ccc;
    couleur: #fff;
    text-align: right;
  }
  & -switch {
    bloc de visualisation;
    largeur: 24px;
    marge: 5px;
    background: #fff;
    position: absolue;
    en haut: 0;
    en bas: 0;
    à droite: 40px;
    bordure: 0 solide #ccc;
    border-radius: 20px;
    transition: tous les 0.3s décrochent les 0;
  }
  & -checkbox: vérifié + & -label {
    .toggle-switch-inner {
      marge gauche: 0;
    }
    .toggle-switch-switch {
      à droite: 0px;
    }
  }
  & .small-switch {
    largeur: 40px;
    .toggle-switch-inner {
      &:après,
      &:avant {
        contenu: "";
        hauteur: 20px;
        hauteur de ligne: 20px;
      }
    }
    .toggle-switch-switch {
      largeur: 16px;
      à droite: 20px;
      marge: 2px;
    }
  }
  Écran @média et (largeur maximale: 991px) {
    transformer: échelle (0,9);
  }
  Écran @média et (largeur maximale: 767px) {
    transformer: échelle (0,825);
  }
  Écran @média et (largeur maximale: 575 pixels) {
    transformer: échelle (0,75);
  }
}

Theming in SCSS

Etant donné que nous pouvons utiliser des variables dans SCSS, la thématisation devient plus facile. L'ajout de la prise en charge de plusieurs thèmes de couleur dans notre application est simplifié avec SCSS. Sass Theming: L'histoire sans fin en explique une partie. Nous allons utiliser certains thèmes de couleur ici et changer toutes les couleurs brutes en variables. Les trois premières lignes constituent un ensemble de couleurs configurable, ce qui nous permet de cibler notre petit contrôle:

 // Colors
$ label-color: #ccc;
$ bascule-couleur: # f90;
$ white: #fff;

// Modes
.interrupteur à bascule {
  position: relative;
  largeur: 75px;
  affichage: inline-block;
  alignement vertical: milieu;
  -webkit-user-select: aucun;
  -moz-user-select: aucun;
  -ms-user-select: none;
  text-align: left;
  & -checkbox {
    affichage: aucun;
  }
  & -label {
    bloc de visualisation;
    débordement caché;
    curseur: pointeur;
    bordure: 0 couleur de l'étiquette $ solide;
    border-radius: 20px;
    marge: 0;
  }
  & -inner {
    bloc de visualisation;
    largeur: 200%;
    marge gauche: -100%;
    transition: la marge 0.3s décroît à 0;
    &:avant,
    &:après {
      bloc de visualisation;
      float: gauche;
      largeur: 50%;
      hauteur: 34px;
      rembourrage: 0;
      hauteur de ligne: 34px;
      taille de police: 14px;
      Couleur blanche;
      poids de police: gras;
      taille de la boîte: boîte à bordure;
    }
    &:avant {
      contenu: attr (data-yes);
      text-transform: majuscule;
      padding-left: 10px;
      couleur d'arrière-plan: $ toggle-color;
      couleur: $ blanc;
    }
  }
  &-désactivé {
    couleur de fond: $ label-color;
    curseur: non autorisé;
    &:avant {
      couleur de fond: $ label-color;
      curseur: non autorisé;
    }
  }
  & -inner: après {
    contenu: attr (no de données);
    text-transform: majuscule;
    padding-right: 10px;
    couleur de fond: $ label-color;
    couleur: $ blanc;
    text-align: right;
  }
  & -switch {
    bloc de visualisation;
    largeur: 24px;
    marge: 5px;
    fond: $ blanc;
    position: absolue;
    en haut: 0;
    en bas: 0;
    à droite: 40px;
    bordure: 0 couleur de l'étiquette $ solide;
    border-radius: 20px;
    transition: tous les 0.3s décrochent les 0;
  }
  & -checkbox: vérifié + & -label {
    .toggle-switch-inner {
      marge gauche: 0;
    }
    .toggle-switch-switch {
      à droite: 0px;
    }
  }
  & .small-switch {
    largeur: 40px;
    .toggle-switch-inner {
      &:après,
      &:avant {
        contenu: "";
        hauteur: 20px;
        hauteur de ligne: 20px;
      }
    }
    .toggle-switch-switch {
      largeur: 16px;
      à droite: 20px;
      marge: 2px;
    }
  }
  Écran @média et (largeur maximale: 991px) {
    transformer: échelle (0,9);
  }
  Écran @média et (largeur maximale: 767px) {
    transformer: échelle (0,825);
  }
  Écran @média et (largeur maximale: 575 pixels) {
    transformer: échelle (0,75);
  }
}

Interactions et JavaScript

Concentrons-nous maintenant sur le fonctionnement du composant de base. Puisque tout dans React se passe à la volée, nous devons utiliser les états pour stocker les informations sur les composants locaux. Juste un rappel amical: chaque fois que vous modifiez une valeur dans l’état d’un composant, la méthode du cycle de vie de render () de React JS est déclenchée. Gardons cela à l’esprit, construisons notre état par défaut:

 state = {
  vérifié: this.props.defaultChecked
};

Nous avons simplement besoin de l'état vérifié . Il s’agit d’une valeur booléenne qui sera reçue d’un support defaultChecked du composant. Nous allons utiliser un static defaultProps dans notre composant de classe comme solution de secours. Cela ressemble au code suivant:

 // Définit le texte pour le rendu.
static defaultProps = {
  Texte: ["Yes", "No"]
}

Comme la plupart des accessoires doivent être configurés par l’utilisateur et que nous ne pouvons pas utiliser de valeurs arbitraires, il est toujours préférable d’arrêter le rendu si les accessoires requis ne sont pas transmis. Cela peut être fait en utilisant une simple déclaration JavaScript si ou un opérateur ternaire utilisant ? : ou un «et» && :

 {this.props.id? (
  
) : nul}

Nous pourrions aussi bien ajouter les écouteurs d'événement utilisant les accessoires du composant comme onChange . Parallèlement à cela, nous pouvons également ajouter quelques accessoires supplémentaires pour les éléments suivants:

  • id (requis): il s’agit du id qui sera transmis au contrôle d’entrée de la case à cocher. Sans ce composant, le composant ne sera pas rendu.
  • Texte (requis): si vous n'utilisez pas la version du contrôle Small vous devrez peut-être le passer à. le commutateur à bascule sous la forme d'un tableau de deux valeurs, qui représentent le texte pour True et False. Un exemple serait Text = {["Yes", "No"]} .
  • Nom (facultatif): ce sera le texte de l'étiquette de l'entrée de case à cocher, mais nous n'utiliserons généralement pas
  • onChange (facultatif): il sera directement transmis au .
  • defaultChecked (facultatif): il sera directement transmis au . ].
  • Small (facultatif): il s'agit d'une valeur booléenne qui rend le commutateur à bascule dans un mode réduit, dans lequel le texte n'est pas restitué.
  • currentValue (facultatif): il sera directement transmis à sous le nom defaultValue .
  • désactivé (facultatif): il sera directement transmis à .

. ] Au fur et à mesure que notre application grandit, nous pouvons attraper beaucoup de bugs avec la vérification de type. React possède des capacités de vérification de type intégrées. Pour exécuter la vérification de type sur les accessoires d'un composant, vous pouvez affecter la propriété spéciale propTypes . Nous pouvons appliquer la liste ci-dessus d'accessoires à l'aide de la bibliothèque PropType de React qui est une bibliothèque séparée qui exporte une plage de validateurs pouvant être utilisés pour garantir la validité des données que vous recevez.

Dans cet exemple , nous utilisons les éléments suivants:

Vous devez importer la bibliothèque PropTypes à l'aide de:

 import PropTypes à partir de "prop-types";

Et après la définition de la classe et avant l’instruction d’exportation, si vous l’avez séparément, nous définirons les PropTypes de la manière suivante:

 ToggleSwitch.propTypes = {
  id: PropTypes.string.isRequired,
  Texte: PropTypes.string.isRequired,
  Nom: PropTypes.string,
  onChange: PropTypes.func,
  defaultChecked: PropTypes.bool,
  Petit: PropTypes.bool,
  currentValue: PropTypes.bool,
  désactivé: PropTypes.bool
};

Avec tous les éléments ci-dessus, notre composant se présente maintenant comme suit:

 import React, {Component} from "react";
importer des PropTypes à partir de "prop-types";

/ *
Composant de commutateur à bascule
Remarque: id est requis pour que le composant ToggleSwitch fonctionne. Name, currentValue, defaultChecked, Small et onChange're en option.
Utilisation: 
* /

la classe ToggleSwitch étend le composant {
  state = {
    vérifié: this.props.defaultChecked
  };
  onChange = e => {
    this.setState ({
      vérifié: e.target.checked
    });
    if (type of this.props.onChange === "fonction") this.props.onChange ();
  };
  render () {
    revenir (
      
{this.props.id? (            ): null}       
    )   }   // Définir le texte pour le rendu.   static defaultProps = {     Texte: ["Yes", "No"]   }; } ToggleSwitch.propTypes = {   id: PropTypes.string.isRequired,   Texte: PropTypes.string.isRequired,   Nom: PropTypes.string,   onChange: PropTypes.func,   defaultChecked: PropTypes.bool,   Petit: PropTypes.bool,   currentValue: PropTypes.bool,   désactivé: PropTypes.bool }; export par défaut ToggleSwitch;

Test unitaire

Tout code créé doit faire l'objet d'un test unitaire, au moins à un niveau élémentaire. Dans mon lieu de travail actuel, nous utilisons des tests unitaires basés sur des instantanés. Nous rechercherons les conditions suivantes dans le composant. Nous utilisons l’enzyme de la bibliothèque de AirBNB à des fins de test et jest en tant que testeur par défaut. En écrivant ces tests, nous nous assurons que notre composant Commutateur à bascule:

  • doit restituer sans plantage
  • doit correspondre à l'instantané
  • doit échouer si l'ID n'est pas fourni
  • doit être restitué si l'ID est fourni
  • devrait désactiver le curseur switch s'il contient des accessoires désactivés

Voici l'intégrale ToggleSwitch.test.js :

 import Réagissez à partir de "react";
importer {peu profond} de "enzyme";
importer ToggleSwitch de "../components/ToggleSwitch";

const text = ["Yes", "No"];
const chkID = "checkboxID";

describe ("composant de commutateur à bascule", () => {
  it ("devrait rendre sans planter", () => {
    const ToggleSwitchComponent = shallow ();
    expect (ToggleSwitchComponent.html ()). not.toHaveLength (0);
  });

  it ("devrait correspondre à l'instantané", () => {
    const ToggleSwitchComponent = shallow ();
    expect (ToggleSwitchComponent) .toMatchSnapshot ();
  });

  it ("devrait échouer si id n'est pas fourni", () => {
    const ToggleSwitchComponent = shallow ();
    expect (ToggleSwitchComponent.find ("label")). toHaveLength (0);
  });

  it ("devrait rendre si id est fourni", () => {
    const ToggleSwitchComponent = shallow (
      
    )
    expect (ToggleSwitchComponent.find ("label")). not.toHaveLength (0);
  });

  it ("devrait désactiver le commutateur switch s'il contient des accessoires désactivés", () => {
    const ToggleSwitchComponent = shallow (
      
    )
    expect (ToggleSwitchComponent.find ("#" + chkID) .props (). désactivé) .toBe (true);
  });
});

Résumé

Vous pouvez obtenir le code source complet auprès de praveenscience / ToggleSwitch: implémentation d'un commutateur à bascule dans React JS en tant que composant réutilisable . Les instructions d'utilisation sont mises à jour dans le référentiel GitHub.

J'espère que vous avez trouvé cet article utile. Si vous avez des commentaires ou des questions, n'hésitez pas à me contacter sur le site Twitter .






Source link